]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/network/networkd-dhcp4.c
Merge pull request #12753 from jrouleau/fix/hibernate-resume-timeout
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
2
3 #include <netinet/in.h>
4 #include <linux/if.h>
5
6 #include "alloc-util.h"
7 #include "hostname-util.h"
8 #include "parse-util.h"
9 #include "network-internal.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-network.h"
13 #include "string-util.h"
14 #include "sysctl-util.h"
15
16 static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, sd_dhcp_lease *new_lease, struct in_addr *address);
17 static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, struct in_addr *address);
18 static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, struct in_addr *address);
19
20 void dhcp4_release_old_lease(Link *link) {
21 union in_addr_union address = IN_ADDR_NULL, address_old = IN_ADDR_NULL;
22
23 assert(link);
24
25 if (!link->dhcp_lease_old)
26 return;
27
28 assert(link->dhcp_lease);
29
30 (void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old.in);
31 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
32
33 (void) dhcp_remove_routes(link, link->dhcp_lease_old, link->dhcp_lease, &address_old.in);
34
35 if (!in_addr_equal(AF_INET, &address_old, &address)) {
36 (void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old.in);
37 (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old.in);
38 }
39
40 link->dhcp_lease_old = sd_dhcp_lease_unref(link->dhcp_lease_old);
41 link_dirty(link);
42 }
43
44 static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
45 int r;
46
47 assert(link);
48 assert(link->dhcp4_messages > 0);
49
50 link->dhcp4_messages--;
51
52 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
53 return 1;
54
55 r = sd_netlink_message_get_errno(m);
56 if (r < 0 && r != -EEXIST) {
57 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
58 link_enter_failed(link);
59 return 1;
60 }
61
62 if (link->dhcp4_messages == 0) {
63 link->dhcp4_configured = true;
64 /* New address and routes are configured now. Let's release old lease. */
65 dhcp4_release_old_lease(link);
66 link_check_ready(link);
67 }
68
69 return 1;
70 }
71
72 static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
73 assert(route);
74 assert(self_addr);
75
76 if (in_addr_is_localhost(AF_INET, &route->dst) ||
77 (self_addr->s_addr && route->dst.in.s_addr == self_addr->s_addr))
78 return RT_SCOPE_HOST;
79 else if (in4_addr_is_null(&route->gw.in))
80 return RT_SCOPE_LINK;
81 else
82 return RT_SCOPE_UNIVERSE;
83 }
84
85 static int link_set_dhcp_routes(Link *link) {
86 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
87 bool classless_route = false, static_route = false;
88 const struct in_addr *router;
89 struct in_addr address;
90 int r, n, i;
91 uint32_t table;
92
93 assert(link);
94
95 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
96 return 0;
97
98 if (!link->network) /* link went down while we configured the IP addresses? */
99 return 0;
100
101 if (!link->network->dhcp_use_routes)
102 return 0;
103
104 table = link_get_dhcp_route_table(link);
105
106 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
107 if (r < 0)
108 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
109
110 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
111 if (n == -ENODATA)
112 log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
113 else if (n < 0)
114 log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");
115
116 for (i = 0; i < n; i++) {
117 switch (sd_dhcp_route_get_option(static_routes[i])) {
118 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
119 classless_route = true;
120 break;
121 case SD_DHCP_OPTION_STATIC_ROUTE:
122 static_route = true;
123 break;
124 }
125 }
126
127 for (i = 0; i < n; i++) {
128 _cleanup_(route_freep) Route *route = NULL;
129
130 /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
131 the DHCP client MUST ignore the Static Routes option. */
132 if (classless_route &&
133 sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
134 continue;
135
136 r = route_new(&route);
137 if (r < 0)
138 return log_link_error_errno(link, r, "Could not allocate route: %m");
139
140 route->family = AF_INET;
141 route->protocol = RTPROT_DHCP;
142 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
143 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
144 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
145 route->priority = link->network->dhcp_route_metric;
146 route->table = table;
147 route->scope = route_scope_from_address(route, &address);
148
149 r = route_configure(route, link, dhcp4_route_handler);
150 if (r < 0)
151 return log_link_error_errno(link, r, "Could not set host route: %m");
152
153 link->dhcp4_messages++;
154 }
155
156 r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
157 if (IN_SET(r, 0, -ENODATA))
158 log_link_info(link, "DHCP: No gateway received from DHCP server.");
159 else if (r < 0)
160 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
161 else if (in4_addr_is_null(&router[0]))
162 log_link_info(link, "DHCP: Received gateway is null.");
163
164 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
165 a Router option, the DHCP client MUST ignore the Router option. */
166 if (classless_route && static_route)
167 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
168
169 if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
170 _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
171
172 r = route_new(&route_gw);
173 if (r < 0)
174 return log_link_error_errno(link, r, "Could not allocate route: %m");
175
176 /* The dhcp netmask may mask out the gateway. Add an explicit
177 * route for the gw host so that we can route no matter the
178 * netmask or existing kernel route tables. */
179 route_gw->family = AF_INET;
180 route_gw->dst.in = router[0];
181 route_gw->dst_prefixlen = 32;
182 route_gw->prefsrc.in = address;
183 route_gw->scope = RT_SCOPE_LINK;
184 route_gw->protocol = RTPROT_DHCP;
185 route_gw->priority = link->network->dhcp_route_metric;
186 route_gw->table = table;
187
188 r = route_configure(route_gw, link, dhcp4_route_handler);
189 if (r < 0)
190 return log_link_error_errno(link, r, "Could not set host route: %m");
191
192 link->dhcp4_messages++;
193
194 r = route_new(&route);
195 if (r < 0)
196 return log_link_error_errno(link, r, "Could not allocate route: %m");
197
198 route->family = AF_INET;
199 route->gw.in = router[0];
200 route->prefsrc.in = address;
201 route->protocol = RTPROT_DHCP;
202 route->priority = link->network->dhcp_route_metric;
203 route->table = table;
204
205 r = route_configure(route, link, dhcp4_route_handler);
206 if (r < 0)
207 return log_link_error_errno(link, r, "Could not set routes: %m");
208
209 link->dhcp4_messages++;
210 }
211
212 return 0;
213 }
214
215 static bool route_present_in_routes(const Route *route, sd_dhcp_route **routes, unsigned n_routes) {
216 assert(n_routes == 0 || routes);
217
218 for (unsigned j = 0; j < n_routes; j++) {
219 union in_addr_union a;
220 unsigned char l;
221
222 assert_se(sd_dhcp_route_get_gateway(routes[j], &a.in) >= 0);
223 if (!in_addr_equal(AF_INET, &a, &route->gw))
224 continue;
225 assert_se(sd_dhcp_route_get_destination(routes[j], &a.in) >= 0);
226 if (!in_addr_equal(AF_INET, &a, &route->dst))
227 continue;
228 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[j], &l) >= 0);
229 if (l != route->dst_prefixlen)
230 continue;
231 return true;
232 }
233
234 return false;
235 }
236
237 static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, sd_dhcp_lease *new_lease, struct in_addr *address) {
238 _cleanup_free_ sd_dhcp_route **routes = NULL, **new_routes = NULL;
239 uint32_t table;
240 int m = 0, n, i, r;
241
242 assert(link);
243 assert(address);
244
245 if (!link->network->dhcp_use_routes)
246 return 0;
247
248 n = sd_dhcp_lease_get_routes(lease, &routes);
249 if (IN_SET(n, 0, -ENODATA))
250 return 0;
251 else if (n < 0)
252 return log_link_error_errno(link, n, "DHCP error: Failed to get routes: %m");
253
254 if (new_lease) {
255 m = sd_dhcp_lease_get_routes(new_lease, &new_routes);
256 if (m == -ENODATA)
257 m = 0;
258 else if (m < 0)
259 return log_link_error_errno(link, m, "DHCP error: Failed to get routes: %m");
260 }
261
262 table = link_get_dhcp_route_table(link);
263
264 for (i = 0; i < n; i++) {
265 _cleanup_(route_freep) Route *route = NULL;
266
267 r = route_new(&route);
268 if (r < 0)
269 return log_oom();
270
271 route->family = AF_INET;
272 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
273 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
274 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
275 route->priority = link->network->dhcp_route_metric;
276 route->table = table;
277 route->scope = route_scope_from_address(route, address);
278
279 if (route_present_in_routes(route, new_routes, m))
280 continue;
281
282 (void) route_remove(route, link, NULL);
283 }
284
285 return n;
286 }
287
288 static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, struct in_addr *address) {
289 _cleanup_(route_freep) Route *route_gw = NULL, *route = NULL;
290 const struct in_addr *router;
291 uint32_t table;
292 int r;
293
294 assert(link);
295 assert(address);
296
297 if (!link->network->dhcp_use_routes)
298 return 0;
299
300 r = sd_dhcp_lease_get_router(lease, &router);
301 if (IN_SET(r, 0, -ENODATA)) {
302 log_link_debug(link, "DHCP: No gateway received from DHCP server.");
303 return 0;
304 } else if (r < 0)
305 return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
306 else if (in4_addr_is_null(&router[0])) {
307 log_link_info(link, "DHCP: Received gateway is null, ignoring.");
308 return 0;
309 }
310
311 table = link_get_dhcp_route_table(link);
312
313 r = route_new(&route_gw);
314 if (r < 0)
315 return log_oom();
316
317 route_gw->family = AF_INET;
318 route_gw->dst.in = router[0];
319 route_gw->dst_prefixlen = 32;
320 route_gw->prefsrc.in = *address;
321 route_gw->scope = RT_SCOPE_LINK;
322 route_gw->protocol = RTPROT_DHCP;
323 route_gw->priority = link->network->dhcp_route_metric;
324 route_gw->table = table;
325
326 (void) route_remove(route_gw, link, NULL);
327
328 r = route_new(&route);
329 if (r < 0)
330 return log_oom();
331
332 route->family = AF_INET;
333 route->gw.in = router[0];
334 route->prefsrc.in = *address;
335 route->protocol = RTPROT_DHCP;
336 route->priority = link->network->dhcp_route_metric;
337 route->table = table;
338
339 (void) route_remove(route, link, NULL);
340
341 return 0;
342 }
343
344 static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, struct in_addr *address) {
345 _cleanup_(address_freep) Address *a = NULL;
346 struct in_addr netmask;
347 int r;
348
349 assert(link);
350 assert(address);
351
352 if (in4_addr_is_null(address))
353 return 0;
354
355 r = address_new(&a);
356 if (r < 0)
357 return log_oom();
358
359 a->family = AF_INET;
360 a->in_addr.in = *address;
361
362 if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
363 a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
364
365 (void) address_remove(a, link, NULL);
366
367 return 0;
368 }
369
370 static int dhcp_reset_mtu(Link *link) {
371 uint16_t mtu;
372 int r;
373
374 assert(link);
375
376 if (!link->network->dhcp_use_mtu)
377 return 0;
378
379 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
380 if (r < 0)
381 return r;
382
383 if (link->original_mtu == mtu)
384 return 0;
385
386 r = link_set_mtu(link, link->original_mtu);
387 if (r < 0) {
388 log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
389 link_enter_failed(link);
390 return r;
391 }
392
393 return 0;
394 }
395
396 static int dhcp_reset_hostname(Link *link) {
397 const char *hostname;
398 int r;
399
400 assert(link);
401
402 if (!link->network->dhcp_use_hostname)
403 return 0;
404
405 hostname = link->network->dhcp_hostname;
406 if (!hostname)
407 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
408
409 if (!hostname)
410 return 0;
411
412 /* If a hostname was set due to the lease, then unset it now. */
413 r = manager_set_hostname(link->manager, NULL);
414 if (r < 0)
415 return log_link_error_errno(link, r, "DHCP error: Failed to reset transient hostname: %m");
416
417 return 0;
418 }
419
420 static int dhcp_lease_lost(Link *link) {
421 struct in_addr address = {};
422
423 assert(link);
424 assert(link->dhcp_lease);
425
426 log_link_warning(link, "DHCP lease lost");
427
428 link->dhcp4_configured = false;
429
430 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
431 (void) dhcp_remove_routes(link, link->dhcp_lease, NULL, &address);
432 (void) dhcp_remove_router(link, link->dhcp_lease, &address);
433 (void) dhcp_remove_address(link, link->dhcp_lease, &address);
434 (void) dhcp_reset_mtu(link);
435 (void) dhcp_reset_hostname(link);
436
437 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
438 link_dirty(link);
439
440 return 0;
441 }
442
443 static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
444 int r;
445
446 assert(link);
447
448 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
449 return 1;
450
451 r = sd_netlink_message_get_errno(m);
452 if (r < 0 && r != -EEXIST) {
453 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
454 link_enter_failed(link);
455 return 1;
456 }
457
458 manager_rtnl_process_address(rtnl, m, link->manager);
459
460 r = link_set_dhcp_routes(link);
461 if (r < 0) {
462 link_enter_failed(link);
463 return 1;
464 }
465
466 /* Add back static routes since kernel removes while DHCPv4 address is removed from when lease expires */
467 link_request_set_routes(link);
468
469 if (link->dhcp4_messages == 0) {
470 link->dhcp4_configured = true;
471 /* The new address is configured, and no route is requested.
472 * Let's drop the old lease. */
473 dhcp4_release_old_lease(link);
474 link_check_ready(link);
475 }
476
477 return 1;
478 }
479
480 static int dhcp4_update_address(Link *link,
481 struct in_addr *address,
482 struct in_addr *netmask,
483 uint32_t lifetime) {
484 _cleanup_(address_freep) Address *addr = NULL;
485 unsigned prefixlen;
486 int r;
487
488 assert(address);
489 assert(netmask);
490 assert(lifetime);
491
492 prefixlen = in4_addr_netmask_to_prefixlen(netmask);
493
494 r = address_new(&addr);
495 if (r < 0)
496 return r;
497
498 addr->family = AF_INET;
499 addr->in_addr.in.s_addr = address->s_addr;
500 addr->cinfo.ifa_prefered = lifetime;
501 addr->cinfo.ifa_valid = lifetime;
502 addr->prefixlen = prefixlen;
503 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
504
505 /* allow reusing an existing address and simply update its lifetime
506 * in case it already exists */
507 r = address_configure(addr, link, dhcp4_address_handler, true);
508 if (r < 0)
509 return r;
510
511 return 0;
512 }
513
514 static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
515 sd_dhcp_lease *lease;
516 struct in_addr address;
517 struct in_addr netmask;
518 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
519 int r;
520
521 assert(link);
522 assert(client);
523 assert(link->network);
524
525 r = sd_dhcp_client_get_lease(client, &lease);
526 if (r < 0)
527 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
528
529 sd_dhcp_lease_unref(link->dhcp_lease);
530 link->dhcp4_configured = false;
531 link->dhcp_lease = sd_dhcp_lease_ref(lease);
532 link_dirty(link);
533
534 r = sd_dhcp_lease_get_address(lease, &address);
535 if (r < 0)
536 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
537
538 r = sd_dhcp_lease_get_netmask(lease, &netmask);
539 if (r < 0)
540 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
541
542 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
543 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
544 if (r < 0)
545 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
546 }
547
548 r = dhcp4_update_address(link, &address, &netmask, lifetime);
549 if (r < 0)
550 return log_link_warning_errno(link, r, "Could not update IP address: %m");
551
552 return 0;
553 }
554
555 static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
556 const struct in_addr *router;
557 sd_dhcp_lease *lease;
558 struct in_addr address;
559 struct in_addr netmask;
560 unsigned prefixlen;
561 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
562 int r;
563
564 assert(client);
565 assert(link);
566
567 link->dhcp4_configured = false;
568
569 r = sd_dhcp_client_get_lease(client, &lease);
570 if (r < 0)
571 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
572
573 r = sd_dhcp_lease_get_address(lease, &address);
574 if (r < 0)
575 return log_link_error_errno(link, r, "DHCP error: No address: %m");
576
577 r = sd_dhcp_lease_get_netmask(lease, &netmask);
578 if (r < 0)
579 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
580
581 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
582
583 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
584 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
585 if (r < 0)
586 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
587 }
588
589 r = sd_dhcp_lease_get_router(lease, &router);
590 if (r < 0 && r != -ENODATA)
591 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
592
593 if (r > 0 && !in4_addr_is_null(&router[0]))
594 log_struct(LOG_INFO,
595 LOG_LINK_INTERFACE(link),
596 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
597 ADDRESS_FMT_VAL(address),
598 prefixlen,
599 ADDRESS_FMT_VAL(router[0])),
600 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
601 "PREFIXLEN=%u", prefixlen,
602 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
603 else
604 log_struct(LOG_INFO,
605 LOG_LINK_INTERFACE(link),
606 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
607 ADDRESS_FMT_VAL(address),
608 prefixlen),
609 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
610 "PREFIXLEN=%u", prefixlen);
611
612 link->dhcp_lease = sd_dhcp_lease_ref(lease);
613 link_dirty(link);
614
615 if (link->network->dhcp_use_mtu) {
616 uint16_t mtu;
617
618 r = sd_dhcp_lease_get_mtu(lease, &mtu);
619 if (r >= 0) {
620 r = link_set_mtu(link, mtu);
621 if (r < 0)
622 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
623 }
624 }
625
626 if (link->network->dhcp_use_hostname) {
627 const char *dhcpname = NULL;
628 _cleanup_free_ char *hostname = NULL;
629
630 if (link->network->dhcp_hostname)
631 dhcpname = link->network->dhcp_hostname;
632 else
633 (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
634
635 if (dhcpname) {
636 r = shorten_overlong(dhcpname, &hostname);
637 if (r < 0)
638 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
639 if (r == 1)
640 log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
641 }
642
643 if (hostname) {
644 r = manager_set_hostname(link->manager, hostname);
645 if (r < 0)
646 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
647 }
648 }
649
650 if (link->network->dhcp_use_timezone) {
651 const char *tz = NULL;
652
653 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
654
655 if (tz) {
656 r = manager_set_timezone(link->manager, tz);
657 if (r < 0)
658 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
659 }
660 }
661
662 r = dhcp4_update_address(link, &address, &netmask, lifetime);
663 if (r < 0)
664 return log_link_warning_errno(link, r, "Could not update IP address: %m");
665
666 return 0;
667 }
668
669 static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
670 int r;
671
672 link->dhcp_lease_old = TAKE_PTR(link->dhcp_lease);
673
674 /* On ip address change, to keep the connectability, we would like to assign new address and
675 * routes, and then release old lease. There are two possible success paths:
676 *
677 * 1. new address and routes are configured.
678 * -> handled by dhcp_release_old_lease() in dhcp4_route_handler().
679 * 2. new address is configured and no route is requested.
680 * -> handled by dhcp_release_old_lease() in dhcp4_address_handler().
681 *
682 * On error in assigning new address and routes, then the link always enters to the failed
683 * state. And link_enter_failed() leads to the DHCP client to be stopped. So,
684 * dhcp_release_old_lease() will be also called by link_stop_clients().
685 */
686
687 r = dhcp_lease_acquired(client, link);
688 if (r < 0) {
689 /* If it fails, then the new address is not configured yet.
690 * So, let's simply drop the old lease. */
691 sd_dhcp_lease_unref(link->dhcp_lease);
692 link->dhcp_lease = TAKE_PTR(link->dhcp_lease_old);
693 (void) dhcp_lease_lost(link);
694 return r;
695 }
696
697 return 0;
698 }
699
700 static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) {
701 sd_dhcp_lease *lease;
702 struct in_addr addr;
703 int r;
704
705 assert(link);
706 assert(link->network);
707 assert(client);
708
709 r = sd_dhcp_client_get_lease(client, &lease);
710 if (r < 0)
711 return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
712
713 r = sd_dhcp_lease_get_server_identifier(lease, &addr);
714 if (r < 0)
715 return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m");
716
717 if (set_contains(link->network->dhcp_black_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
718 log_struct(LOG_DEBUG,
719 LOG_LINK_INTERFACE(link),
720 LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in black listed ip addresses, ignoring offer",
721 ADDRESS_FMT_VAL(addr)));
722 return true;
723 }
724
725 return false;
726 }
727
728 static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
729 Link *link = userdata;
730 int r;
731
732 assert(link);
733 assert(link->network);
734 assert(link->manager);
735
736 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
737 return 0;
738
739 switch (event) {
740 case SD_DHCP_CLIENT_EVENT_STOP:
741
742 if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) {
743 assert(link->ipv4ll);
744
745 log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
746
747 r = sd_ipv4ll_start(link->ipv4ll);
748 if (r < 0)
749 return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
750 }
751
752 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
753 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
754 return 0;
755 }
756
757 if (link->network->dhcp_send_release)
758 (void) sd_dhcp_client_send_release(client);
759
760 if (link->dhcp_lease) {
761 r = dhcp_lease_lost(link);
762 if (r < 0) {
763 link_enter_failed(link);
764 return r;
765 }
766 }
767
768 break;
769 case SD_DHCP_CLIENT_EVENT_EXPIRED:
770 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
771 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
772 return 0;
773 }
774
775 if (link->dhcp_lease) {
776 r = dhcp_lease_lost(link);
777 if (r < 0) {
778 link_enter_failed(link);
779 return r;
780 }
781 }
782
783 break;
784 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
785 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
786 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
787 return 0;
788 }
789
790 r = dhcp_lease_ip_change(client, link);
791 if (r < 0) {
792 link_enter_failed(link);
793 return r;
794 }
795
796 break;
797 case SD_DHCP_CLIENT_EVENT_RENEW:
798 r = dhcp_lease_renew(client, link);
799 if (r < 0) {
800 link_enter_failed(link);
801 return r;
802 }
803 break;
804 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
805 r = dhcp_lease_acquired(client, link);
806 if (r < 0) {
807 link_enter_failed(link);
808 return r;
809 }
810 break;
811 case SD_DHCP_CLIENT_EVENT_SELECTING:
812 r = dhcp_server_is_black_listed(link, client);
813 if (r < 0)
814 return r;
815 if (r != 0)
816 return -ENOMSG;
817 break;
818 default:
819 if (event < 0)
820 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
821 else
822 log_link_warning(link, "DHCP unknown event: %i", event);
823 break;
824 }
825
826 return 0;
827 }
828
829 static int dhcp4_set_hostname(Link *link) {
830 _cleanup_free_ char *hostname = NULL;
831 const char *hn;
832 int r;
833
834 assert(link);
835
836 if (!link->network->dhcp_send_hostname)
837 hn = NULL;
838 else if (link->network->dhcp_hostname)
839 hn = link->network->dhcp_hostname;
840 else {
841 r = gethostname_strict(&hostname);
842 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
843 return r;
844
845 hn = hostname;
846 }
847
848 r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
849 if (r == -EINVAL && hostname)
850 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
851 log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
852 else if (r < 0)
853 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
854
855 return 0;
856 }
857
858 static bool promote_secondaries_enabled(const char *ifname) {
859 _cleanup_free_ char *promote_secondaries_sysctl = NULL;
860 char *promote_secondaries_path;
861 int r;
862
863 promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
864 r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
865 if (r < 0) {
866 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
867 return false;
868 }
869
870 truncate_nl(promote_secondaries_sysctl);
871 r = parse_boolean(promote_secondaries_sysctl);
872 if (r < 0)
873 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
874 return r > 0;
875 }
876
877 /* dhcp4_set_promote_secondaries will ensure this interface has
878 * the "promote_secondaries" option in the kernel set. If this sysctl
879 * is not set DHCP will work only as long as the IP address does not
880 * changes between leases. The kernel will remove all secondary IP
881 * addresses of an interface otherwise. The way systemd-network works
882 * is that the new IP of a lease is added as a secondary IP and when
883 * the primary one expires it relies on the kernel to promote the
884 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
885 */
886 int dhcp4_set_promote_secondaries(Link *link) {
887 int r;
888
889 assert(link);
890 assert(link->network);
891 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
892
893 /* check if the kernel has promote_secondaries enabled for our
894 * interface. If it is not globally enabled or enabled for the
895 * specific interface we must either enable it.
896 */
897 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
898 char *promote_secondaries_path = NULL;
899
900 log_link_debug(link, "promote_secondaries is unset, setting it");
901 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
902 r = sysctl_write(promote_secondaries_path, "1");
903 if (r < 0)
904 log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
905 return r > 0;
906 }
907
908 return 0;
909 }
910
911 int dhcp4_set_client_identifier(Link *link) {
912 int r;
913
914 assert(link);
915 assert(link->network);
916 assert(link->dhcp_client);
917
918 switch (link->network->dhcp_client_identifier) {
919 case DHCP_CLIENT_ID_DUID: {
920 /* If configured, apply user specified DUID and IAID */
921 const DUID *duid = link_get_duid(link);
922
923 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
924 r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
925 link->network->iaid_set,
926 link->network->iaid,
927 duid->llt_time);
928 else
929 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
930 link->network->iaid_set,
931 link->network->iaid,
932 duid->type,
933 duid->raw_data_len > 0 ? duid->raw_data : NULL,
934 duid->raw_data_len);
935 if (r < 0)
936 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
937 break;
938 }
939 case DHCP_CLIENT_ID_DUID_ONLY: {
940 /* If configured, apply user specified DUID */
941 const DUID *duid = link_get_duid(link);
942
943 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
944 r = sd_dhcp_client_set_duid_llt(link->dhcp_client,
945 duid->llt_time);
946 else
947 r = sd_dhcp_client_set_duid(link->dhcp_client,
948 duid->type,
949 duid->raw_data_len > 0 ? duid->raw_data : NULL,
950 duid->raw_data_len);
951 if (r < 0)
952 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
953 break;
954 }
955 case DHCP_CLIENT_ID_MAC:
956 r = sd_dhcp_client_set_client_id(link->dhcp_client,
957 ARPHRD_ETHER,
958 (const uint8_t *) &link->mac,
959 sizeof(link->mac));
960 if (r < 0)
961 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
962 break;
963 default:
964 assert_not_reached("Unknown client identifier type.");
965 }
966
967 return 0;
968 }
969
970 int dhcp4_configure(Link *link) {
971 int r;
972
973 assert(link);
974 assert(link->network);
975 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
976
977 if (!link->dhcp_client) {
978 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
979 if (r == -ENOMEM)
980 return log_oom();
981 if (r < 0)
982 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to create DHCP4 client: %m");
983 }
984
985 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
986 if (r < 0)
987 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to attach event: %m");
988
989 r = sd_dhcp_client_set_mac(link->dhcp_client,
990 (const uint8_t *) &link->mac,
991 sizeof (link->mac), ARPHRD_ETHER);
992 if (r < 0)
993 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
994
995 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
996 if (r < 0)
997 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
998
999 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
1000 if (r < 0)
1001 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
1002
1003 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
1004 link->network->dhcp_broadcast);
1005 if (r < 0)
1006 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
1007
1008 if (link->mtu) {
1009 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
1010 if (r < 0)
1011 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
1012 }
1013
1014 if (link->network->dhcp_use_mtu) {
1015 r = sd_dhcp_client_set_request_option(link->dhcp_client,
1016 SD_DHCP_OPTION_INTERFACE_MTU);
1017 if (r < 0)
1018 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
1019 }
1020
1021 /* NOTE: even if this variable is called "use", it also "sends" PRL
1022 * options, maybe there should be a different configuration variable
1023 * to send or not route options?. */
1024 /* NOTE: when using Anonymize=yes, routes PRL options are sent
1025 * by default, so they don't need to be added here. */
1026 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
1027 r = sd_dhcp_client_set_request_option(link->dhcp_client,
1028 SD_DHCP_OPTION_STATIC_ROUTE);
1029 if (r < 0)
1030 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
1031
1032 r = sd_dhcp_client_set_request_option(link->dhcp_client,
1033 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
1034 if (r < 0)
1035 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
1036 }
1037
1038 if (link->network->dhcp_use_ntp) {
1039 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
1040 if (r < 0)
1041 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
1042 }
1043
1044 if (link->network->dhcp_use_timezone) {
1045 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
1046 if (r < 0)
1047 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
1048 }
1049
1050 r = dhcp4_set_hostname(link);
1051 if (r < 0)
1052 return r;
1053
1054 if (link->network->dhcp_vendor_class_identifier) {
1055 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
1056 link->network->dhcp_vendor_class_identifier);
1057 if (r < 0)
1058 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
1059 }
1060
1061 if (link->network->dhcp_user_class) {
1062 r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
1063 if (r < 0)
1064 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
1065 }
1066
1067 if (link->network->dhcp_client_port) {
1068 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
1069 if (r < 0)
1070 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
1071 }
1072
1073 if (link->network->dhcp_max_attempts > 0) {
1074 r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
1075 if (r < 0)
1076 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
1077 }
1078
1079 return dhcp4_set_client_identifier(link);
1080 }