]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp4.c
networkd: fix promote_secondaries logic
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3c9b8860
TG
2/***
3 This file is part of systemd.
4
5 Copyright 2013-2014 Tom Gundersen <teg@jklm.no>
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
21#include <netinet/ether.h>
22#include <linux/if.h>
23
b5efdb8a
LP
24#include "alloc-util.h"
25#include "dhcp-lease-internal.h"
958b66ea 26#include "hostname-util.h"
64b21ece 27#include "parse-util.h"
fc1ba79d 28#include "netdev/vrf.h"
3c9b8860 29#include "network-internal.h"
23f53b99
TG
30#include "networkd-link.h"
31#include "networkd-manager.h"
32#include "networkd-network.h"
64b21ece
MV
33#include "string-util.h"
34#include "sysctl-util.h"
3c9b8860 35
1c4baffc 36static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m,
3c9b8860
TG
37 void *userdata) {
38 _cleanup_link_unref_ Link *link = userdata;
39 int r;
40
41 assert(link);
6cf4a01c 42 assert(link->dhcp4_messages > 0);
3c9b8860 43
313cefa1 44 link->dhcp4_messages--;
3c9b8860 45
1c4baffc 46 r = sd_netlink_message_get_errno(m);
3c9b8860 47 if (r < 0 && r != -EEXIST) {
f6b8196f 48 log_link_error_errno(link, r, "Could not set DHCPv4 route: %m");
3c9b8860
TG
49 link_enter_failed(link);
50 }
51
6cf4a01c 52 if (link->dhcp4_messages == 0) {
3c9b8860 53 link->dhcp4_configured = true;
8012cd39 54 link_check_ready(link);
3c9b8860
TG
55 }
56
57 return 1;
58}
59
d6eac9bd
DW
60static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
61 assert(route);
62 assert(self_addr);
63
64 if (in_addr_is_localhost(AF_INET, &route->dst) ||
65 (self_addr->s_addr && route->dst.in.s_addr == self_addr->s_addr))
66 return RT_SCOPE_HOST;
67 else if (in4_addr_is_null(&route->gw.in))
68 return RT_SCOPE_LINK;
69 else
70 return RT_SCOPE_UNIVERSE;
71}
72
3c9b8860 73static int link_set_dhcp_routes(Link *link) {
d6eac9bd 74 struct in_addr gateway, address;
f8693fc7 75 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
3c9b8860 76 int r, n, i;
fc1ba79d 77 uint32_t table;
3c9b8860
TG
78
79 assert(link);
0c9b15a3
AJ
80
81 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
82 return 0;
83
84 if (!link->network) /* link went down while we configured the IP addresses? */
85 return 0;
964b26fe
SS
86
87 if (!link->network->dhcp_use_routes)
88 return 0;
3c9b8860 89
fc1ba79d
AR
90 /* When the interface is part of an VRF use the VRFs routing table, unless
91 * there is a another table specified. */
92 table = link->network->dhcp_route_table;
93 if (!link->network->dhcp_route_table_set && link->network->vrf != NULL)
94 table = VRF(link->network->vrf)->table;
95
b23aec0d
DW
96 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
97 if (r < 0)
98 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
99
5f04a209 100 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
5f04a209 101 if (n < 0)
8dc787d1 102 log_link_debug_errno(link, n, "DHCP error: could not get routes: %m");
5f04a209
SS
103
104 for (i = 0; i < n; i++) {
105 _cleanup_route_free_ Route *route = NULL;
106
107 r = route_new(&route);
108 if (r < 0)
109 return log_link_error_errno(link, r, "Could not allocate route: %m");
110
111 route->family = AF_INET;
112 route->protocol = RTPROT_DHCP;
113 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
114 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
115 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
116 route->priority = link->network->dhcp_route_metric;
117 route->table = table;
118 route->scope = route_scope_from_address(route, &address);
119
120 r = route_configure(route, link, dhcp4_route_handler);
121 if (r < 0)
122 return log_link_warning_errno(link, r, "Could not set host route: %m");
123
124 link->dhcp4_messages++;
125 }
126
3c9b8860 127 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
444b0170
SS
128 if (r == -ENODATA)
129 log_link_info_errno(link, r, "DHCP: No routes received from DHCP server: %m");
130 else if (r < 0)
131 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
f6b8196f 132
5f04a209
SS
133 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
134 a Router option, the DHCP client MUST ignore the Router option. */
135 if (r >= 0 && link->dhcp4_messages <= 0) {
3c9b8860
TG
136 _cleanup_route_free_ Route *route = NULL;
137 _cleanup_route_free_ Route *route_gw = NULL;
138
ed9e361a 139 r = route_new(&route);
f6b8196f
LP
140 if (r < 0)
141 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860 142
ed9e361a
TG
143 route->protocol = RTPROT_DHCP;
144
145 r = route_new(&route_gw);
f6b8196f
LP
146 if (r < 0)
147 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860
TG
148
149 /* The dhcp netmask may mask out the gateway. Add an explicit
150 * route for the gw host so that we can route no matter the
151 * netmask or existing kernel route tables. */
152 route_gw->family = AF_INET;
2ce40956 153 route_gw->dst.in = gateway;
3c9b8860 154 route_gw->dst_prefixlen = 32;
2ce40956 155 route_gw->prefsrc.in = address;
3c9b8860 156 route_gw->scope = RT_SCOPE_LINK;
ed9e361a 157 route_gw->protocol = RTPROT_DHCP;
86655331 158 route_gw->priority = link->network->dhcp_route_metric;
fc1ba79d 159 route_gw->table = table;
3c9b8860 160
483d099e 161 r = route_configure(route_gw, link, dhcp4_route_handler);
f6b8196f
LP
162 if (r < 0)
163 return log_link_warning_errno(link, r, "Could not set host route: %m");
3c9b8860 164
313cefa1 165 link->dhcp4_messages++;
3c9b8860
TG
166
167 route->family = AF_INET;
2ce40956
TG
168 route->gw.in = gateway;
169 route->prefsrc.in = address;
86655331 170 route->priority = link->network->dhcp_route_metric;
fc1ba79d 171 route->table = table;
3c9b8860 172
483d099e 173 r = route_configure(route, link, dhcp4_route_handler);
3c9b8860 174 if (r < 0) {
f6b8196f 175 log_link_warning_errno(link, r, "Could not set routes: %m");
3c9b8860
TG
176 link_enter_failed(link);
177 return r;
178 }
179
313cefa1 180 link->dhcp4_messages++;
3c9b8860
TG
181 }
182
3c9b8860
TG
183 return 0;
184}
185
186static int dhcp_lease_lost(Link *link) {
187 _cleanup_address_free_ Address *address = NULL;
188 struct in_addr addr;
189 struct in_addr netmask;
190 struct in_addr gateway;
f414a269 191 unsigned prefixlen = 0;
3c9b8860
TG
192 int r;
193
194 assert(link);
195 assert(link->dhcp_lease);
196
79008bdd 197 log_link_warning(link, "DHCP lease lost");
3c9b8860 198
27cb34f5 199 if (link->network->dhcp_use_routes) {
f8693fc7 200 _cleanup_free_ sd_dhcp_route **routes = NULL;
3c9b8860
TG
201 int n, i;
202
203 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &routes);
204 if (n >= 0) {
205 for (i = 0; i < n; i++) {
206 _cleanup_route_free_ Route *route = NULL;
207
ed9e361a 208 r = route_new(&route);
3c9b8860
TG
209 if (r >= 0) {
210 route->family = AF_INET;
f8693fc7
BG
211 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
212 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
213 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
3c9b8860 214
91b5f997 215 route_remove(route, link,
483d099e 216 link_route_remove_handler);
3c9b8860
TG
217 }
218 }
219 }
220 }
221
f0213e37 222 r = address_new(&address);
3c9b8860
TG
223 if (r >= 0) {
224 r = sd_dhcp_lease_get_router(link->dhcp_lease, &gateway);
225 if (r >= 0) {
226 _cleanup_route_free_ Route *route_gw = NULL;
227 _cleanup_route_free_ Route *route = NULL;
228
ed9e361a 229 r = route_new(&route_gw);
3c9b8860
TG
230 if (r >= 0) {
231 route_gw->family = AF_INET;
2ce40956 232 route_gw->dst.in = gateway;
3c9b8860
TG
233 route_gw->dst_prefixlen = 32;
234 route_gw->scope = RT_SCOPE_LINK;
235
91b5f997 236 route_remove(route_gw, link,
483d099e 237 link_route_remove_handler);
3c9b8860
TG
238 }
239
ed9e361a 240 r = route_new(&route);
3c9b8860
TG
241 if (r >= 0) {
242 route->family = AF_INET;
2ce40956 243 route->gw.in = gateway;
3c9b8860 244
91b5f997 245 route_remove(route, link,
483d099e 246 link_route_remove_handler);
3c9b8860
TG
247 }
248 }
249
f414a269
TG
250 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr);
251 if (r >= 0) {
252 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
253 if (r >= 0)
5a941f5f 254 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
3c9b8860 255
f414a269
TG
256 address->family = AF_INET;
257 address->in_addr.in = addr;
258 address->prefixlen = prefixlen;
3c9b8860 259
483d099e 260 address_remove(address, link, link_address_remove_handler);
f414a269 261 }
3c9b8860
TG
262 }
263
27cb34f5 264 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
265 uint16_t mtu;
266
267 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
268 if (r >= 0 && link->original_mtu != mtu) {
269 r = link_set_mtu(link, link->original_mtu);
270 if (r < 0) {
79008bdd 271 log_link_warning(link,
3c9b8860
TG
272 "DHCP error: could not reset MTU");
273 link_enter_failed(link);
274 return r;
275 }
276 }
277 }
278
27cb34f5 279 if (link->network->dhcp_use_hostname) {
3c9b8860
TG
280 const char *hostname = NULL;
281
27cb34f5
LP
282 if (link->network->dhcp_hostname)
283 hostname = link->network->dhcp_hostname;
dce391e7
LP
284 else
285 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
a7d0ef44 286
dce391e7
LP
287 if (hostname) {
288 /* If a hostname was set due to the lease, then unset it now. */
59eb33e0 289 r = manager_set_hostname(link->manager, NULL);
3c9b8860 290 if (r < 0)
dce391e7 291 log_link_warning_errno(link, r, "Failed to reset transient hostname: %m");
3c9b8860
TG
292 }
293 }
294
295 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
6a3e5f6a 296 link_dirty(link);
3c9b8860
TG
297 link->dhcp4_configured = false;
298
299 return 0;
300}
301
1c4baffc 302static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m,
3c9b8860
TG
303 void *userdata) {
304 _cleanup_link_unref_ Link *link = userdata;
305 int r;
306
307 assert(link);
308
1c4baffc 309 r = sd_netlink_message_get_errno(m);
3c9b8860 310 if (r < 0 && r != -EEXIST) {
f6b8196f 311 log_link_error_errno(link, r, "Could not set DHCPv4 address: %m");
3c9b8860 312 link_enter_failed(link);
45af44d4 313 } else if (r >= 0)
200a0868 314 manager_rtnl_process_address(rtnl, m, link->manager);
3c9b8860
TG
315
316 link_set_dhcp_routes(link);
317
318 return 1;
319}
320
321static int dhcp4_update_address(Link *link,
322 struct in_addr *address,
323 struct in_addr *netmask,
324 uint32_t lifetime) {
325 _cleanup_address_free_ Address *addr = NULL;
326 unsigned prefixlen;
327 int r;
328
329 assert(address);
330 assert(netmask);
331 assert(lifetime);
332
5a941f5f 333 prefixlen = in4_addr_netmask_to_prefixlen(netmask);
3c9b8860 334
f0213e37 335 r = address_new(&addr);
3c9b8860
TG
336 if (r < 0)
337 return r;
338
339 addr->family = AF_INET;
340 addr->in_addr.in.s_addr = address->s_addr;
341 addr->cinfo.ifa_prefered = lifetime;
342 addr->cinfo.ifa_valid = lifetime;
343 addr->prefixlen = prefixlen;
344 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
345
66669078
TG
346 /* allow reusing an existing address and simply update its lifetime
347 * in case it already exists */
483d099e 348 r = address_configure(addr, link, dhcp4_address_handler, true);
3c9b8860
TG
349 if (r < 0)
350 return r;
351
352 return 0;
353}
354
355static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
356 sd_dhcp_lease *lease;
357 struct in_addr address;
358 struct in_addr netmask;
359 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
360 int r;
361
362 assert(link);
363 assert(client);
364 assert(link->network);
365
366 r = sd_dhcp_client_get_lease(client, &lease);
f6b8196f
LP
367 if (r < 0)
368 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
3c9b8860
TG
369
370 sd_dhcp_lease_unref(link->dhcp_lease);
371 link->dhcp4_configured = false;
e6b18ffa 372 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 373 link_dirty(link);
3c9b8860
TG
374
375 r = sd_dhcp_lease_get_address(lease, &address);
f6b8196f
LP
376 if (r < 0)
377 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
3c9b8860
TG
378
379 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f6b8196f
LP
380 if (r < 0)
381 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
3c9b8860
TG
382
383 if (!link->network->dhcp_critical) {
f6b8196f
LP
384 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
385 if (r < 0)
386 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
3c9b8860
TG
387 }
388
389 r = dhcp4_update_address(link, &address, &netmask, lifetime);
390 if (r < 0) {
f6b8196f 391 log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
392 link_enter_failed(link);
393 return r;
394 }
395
396 return 0;
397}
398
399static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
400 sd_dhcp_lease *lease;
401 struct in_addr address;
402 struct in_addr netmask;
403 struct in_addr gateway;
404 unsigned prefixlen;
405 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
406 int r;
407
408 assert(client);
409 assert(link);
410
411 r = sd_dhcp_client_get_lease(client, &lease);
f2341e0a 412 if (r < 0)
f6b8196f 413 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
3c9b8860
TG
414
415 r = sd_dhcp_lease_get_address(lease, &address);
f2341e0a 416 if (r < 0)
f6b8196f 417 return log_link_error_errno(link, r, "DHCP error: No address: %m");
3c9b8860
TG
418
419 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f2341e0a 420 if (r < 0)
f6b8196f 421 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
3c9b8860 422
5a941f5f 423 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
3c9b8860
TG
424
425 r = sd_dhcp_lease_get_router(lease, &gateway);
397d15fd 426 if (r < 0 && r != -ENODATA)
f6b8196f 427 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
3c9b8860
TG
428
429 if (r >= 0)
f2341e0a
LP
430 log_struct(LOG_INFO,
431 LOG_LINK_INTERFACE(link),
432 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
433 ADDRESS_FMT_VAL(address),
434 prefixlen,
435 ADDRESS_FMT_VAL(gateway)),
436 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
437 "PREFIXLEN=%u", prefixlen,
438 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(gateway),
439 NULL);
3c9b8860 440 else
f2341e0a
LP
441 log_struct(LOG_INFO,
442 LOG_LINK_INTERFACE(link),
443 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
444 ADDRESS_FMT_VAL(address),
445 prefixlen),
446 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
447 "PREFIXLEN=%u", prefixlen,
448 NULL);
3c9b8860 449
e6b18ffa 450 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 451 link_dirty(link);
3c9b8860 452
27cb34f5 453 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
454 uint16_t mtu;
455
456 r = sd_dhcp_lease_get_mtu(lease, &mtu);
457 if (r >= 0) {
458 r = link_set_mtu(link, mtu);
459 if (r < 0)
f2341e0a 460 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
3c9b8860
TG
461 }
462 }
463
27cb34f5 464 if (link->network->dhcp_use_hostname) {
49f6e11e 465 const char *hostname = NULL;
3c9b8860 466
27cb34f5
LP
467 if (link->network->dhcp_hostname)
468 hostname = link->network->dhcp_hostname;
dce391e7
LP
469 else
470 (void) sd_dhcp_lease_get_hostname(lease, &hostname);
a7d0ef44 471
dce391e7 472 if (hostname) {
59eb33e0 473 r = manager_set_hostname(link->manager, hostname);
3c9b8860 474 if (r < 0)
f2341e0a 475 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
3c9b8860
TG
476 }
477 }
478
27cb34f5 479 if (link->network->dhcp_use_timezone) {
21b80ad1
LP
480 const char *tz = NULL;
481
482 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
483
484 if (tz) {
59eb33e0 485 r = manager_set_timezone(link->manager, tz);
21b80ad1
LP
486 if (r < 0)
487 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
488 }
489 }
490
3c9b8860 491 if (!link->network->dhcp_critical) {
f2341e0a 492 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
3c9b8860 493 if (r < 0) {
f2341e0a 494 log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
3c9b8860
TG
495 return r;
496 }
497 }
498
499 r = dhcp4_update_address(link, &address, &netmask, lifetime);
500 if (r < 0) {
f2341e0a 501 log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
502 link_enter_failed(link);
503 return r;
504 }
505
506 return 0;
507}
508static void dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
509 Link *link = userdata;
510 int r = 0;
511
512 assert(link);
513 assert(link->network);
514 assert(link->manager);
515
516 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
517 return;
518
519 switch (event) {
03748142
DH
520 case SD_DHCP_CLIENT_EVENT_EXPIRED:
521 case SD_DHCP_CLIENT_EVENT_STOP:
522 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
3c9b8860 523 if (link->network->dhcp_critical) {
f6b8196f 524 log_link_error(link, "DHCPv4 connection considered system critical, ignoring request to reconfigure it.");
3c9b8860
TG
525 return;
526 }
527
528 if (link->dhcp_lease) {
529 r = dhcp_lease_lost(link);
530 if (r < 0) {
531 link_enter_failed(link);
532 return;
533 }
534 }
535
03748142 536 if (event == SD_DHCP_CLIENT_EVENT_IP_CHANGE) {
3c9b8860
TG
537 r = dhcp_lease_acquired(client, link);
538 if (r < 0) {
539 link_enter_failed(link);
540 return;
541 }
542 }
543
544 break;
03748142 545 case SD_DHCP_CLIENT_EVENT_RENEW:
3c9b8860
TG
546 r = dhcp_lease_renew(client, link);
547 if (r < 0) {
548 link_enter_failed(link);
549 return;
550 }
551 break;
03748142 552 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
3c9b8860
TG
553 r = dhcp_lease_acquired(client, link);
554 if (r < 0) {
555 link_enter_failed(link);
556 return;
557 }
558 break;
559 default:
560 if (event < 0)
f6b8196f 561 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
3c9b8860 562 else
f6b8196f 563 log_link_warning(link, "DHCP unknown event: %i", event);
3c9b8860
TG
564 break;
565 }
566
567 return;
568}
569
7192bb81
LP
570static int dhcp4_set_hostname(Link *link) {
571 _cleanup_free_ char *hostname = NULL;
572 const char *hn;
573 int r;
574
575 assert(link);
576
577 if (!link->network->dhcp_send_hostname)
578 hn = NULL;
579 else if (link->network->dhcp_hostname)
580 hn = link->network->dhcp_hostname;
581 else {
582 r = gethostname_strict(&hostname);
583 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
584 return r;
585
586 hn = hostname;
587 }
588
589 return sd_dhcp_client_set_hostname(link->dhcp_client, hn);
590}
591
64b21ece
MV
592static bool promote_secondaries_enabled(const char *ifname) {
593 char *promote_secondaries_sysctl, *promote_secondaries_path;
594 int r;
595
596 promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
597 r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
598 if (r < 0) {
599 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
600 return false;
601 }
602
603 truncate_nl(promote_secondaries_sysctl);
604 r = parse_boolean(promote_secondaries_sysctl);
605 if (r < 0)
606 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
607 return r > 0;
608}
609
610/* dhcp4_set_promote_secondaries will ensure this interface has
611 * the "promote_secondaries" option in the kernel set. If this sysctl
612 * is not set DHCP will work only as long as the IP address does not
613 * changes between leases. The kernel will remove all secondary IP
614 * addresses of an interface otherwise. The way systemd-network works
615 * is that the new IP of a lease is added as a secondary IP and when
616 * the primary one expires it relies on the kernel to promote the
617 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
618 */
619int dhcp4_set_promote_secondaries(Link *link) {
620 int r;
621
622 assert(link);
623 assert(link->network);
624 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
625
626 /* check if the kernel has promote_secondaries enabled for our
627 * interface. If it is not globally enabled or enabled for the
628 * specific interface we must either enable it.
629 */
8e1a7253 630 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
64b21ece
MV
631 char *promote_secondaries_path = NULL;
632
633 log_link_debug(link, "promote_secondaries is unset, setting it");
634 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
635 r = sysctl_write(promote_secondaries_path, "1");
636 if (r < 0)
637 log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
638 return r > 0;
639 }
640
641 return 0;
642}
643
3c9b8860
TG
644int dhcp4_configure(Link *link) {
645 int r;
646
647 assert(link);
648 assert(link->network);
e0ee46f2 649 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
3c9b8860 650
0bc70f1d 651 if (!link->dhcp_client) {
db3d2358 652 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
0bc70f1d
TG
653 if (r < 0)
654 return r;
655 }
3c9b8860
TG
656
657 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
658 if (r < 0)
659 return r;
660
76253e73
DW
661 r = sd_dhcp_client_set_mac(link->dhcp_client,
662 (const uint8_t *) &link->mac,
663 sizeof (link->mac), ARPHRD_ETHER);
3c9b8860
TG
664 if (r < 0)
665 return r;
666
2f8e7633 667 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
3c9b8860
TG
668 if (r < 0)
669 return r;
670
671 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
672 if (r < 0)
673 return r;
674
675 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
676 link->network->dhcp_broadcast);
677 if (r < 0)
678 return r;
679
680 if (link->mtu) {
681 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
682 if (r < 0)
683 return r;
684 }
685
27cb34f5 686 if (link->network->dhcp_use_mtu) {
39745a5a 687 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 688 SD_DHCP_OPTION_INTERFACE_MTU);
39745a5a
LP
689 if (r < 0)
690 return r;
3c9b8860
TG
691 }
692
5e77a146 693 /* NOTE: even if this variable is called "use", it also "sends" PRL
694 * options, maybe there should be a different configuration variable
695 * to send or not route options?. */
28522b0d 696 /* NOTE: when using Anonymize=yes, routes PRL options are sent
697 * by default, so they don't need to be added here. */
5e77a146 698 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
3c9b8860 699 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 700 SD_DHCP_OPTION_STATIC_ROUTE);
3c9b8860
TG
701 if (r < 0)
702 return r;
703 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 704 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
7d6884b6
TA
705 if (r < 0)
706 return r;
3c9b8860
TG
707 }
708
ead36ce6 709 if (link->network->dhcp_use_ntp) {
710 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
711 if (r < 0)
712 return r;
713 }
4b7b5abb 714
89573b37 715 if (link->network->dhcp_use_timezone) {
716 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
717 if (r < 0)
718 return r;
719 }
8eb9058d 720
7192bb81
LP
721 r = dhcp4_set_hostname(link);
722 if (r < 0)
723 return r;
3c9b8860
TG
724
725 if (link->network->dhcp_vendor_class_identifier) {
726 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
727 link->network->dhcp_vendor_class_identifier);
728 if (r < 0)
729 return r;
730 }
731
9faed222
SS
732 if (link->network->dhcp_client_port) {
733 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
734 if (r < 0)
735 return r;
736 }
737
3e43b2cd 738 switch (link->network->dhcp_client_identifier) {
8341a5c3 739 case DHCP_CLIENT_ID_DUID: {
413708d1 740 /* If configured, apply user specified DUID and/or IAID */
8341a5c3
ZJS
741 const DUID *duid = link_duid(link);
742
743 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
744 link->network->iaid,
745 duid->type,
746 duid->raw_data_len > 0 ? duid->raw_data : NULL,
747 duid->raw_data_len);
413708d1
VK
748 if (r < 0)
749 return r;
3e43b2cd 750 break;
8341a5c3 751 }
3e43b2cd
JJ
752 case DHCP_CLIENT_ID_MAC:
753 r = sd_dhcp_client_set_client_id(link->dhcp_client,
754 ARPHRD_ETHER,
755 (const uint8_t *) &link->mac,
8341a5c3 756 sizeof(link->mac));
3e43b2cd
JJ
757 if (r < 0)
758 return r;
759 break;
760 default:
761 assert_not_reached("Unknown client identifier type.");
762 }
763
3c9b8860
TG
764 return 0;
765}