]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp4.c
Merge pull request #14329 from anitazha/user_invocation_id
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
3c9b8860 2
9aa5d8ba 3#include <netinet/in.h>
3c9b8860 4#include <linux/if.h>
8f815e8b 5#include <linux/if_arp.h>
3c9b8860 6
b5efdb8a 7#include "alloc-util.h"
cb29c156 8#include "dhcp-client-internal.h"
958b66ea 9#include "hostname-util.h"
64b21ece 10#include "parse-util.h"
3c9b8860 11#include "network-internal.h"
ca5ad760 12#include "networkd-dhcp4.h"
23f53b99
TG
13#include "networkd-link.h"
14#include "networkd-manager.h"
15#include "networkd-network.h"
ca5ad760 16#include "string-table.h"
64b21ece
MV
17#include "string-util.h"
18#include "sysctl-util.h"
3c9b8860 19
d4c52ee5
YW
20static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
21static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
854a1ccf 22static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all);
dd9b10c8
YW
23static int dhcp_remove_address(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, link_netlink_message_handler_t callback);
24static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link);
25static int dhcp_lease_renew(sd_dhcp_client *client, Link *link);
d03073dd
YW
26
27void dhcp4_release_old_lease(Link *link) {
d4c52ee5 28 struct in_addr address = {}, address_old = {};
d03073dd
YW
29
30 assert(link);
31
32 if (!link->dhcp_lease_old)
33 return;
34
35 assert(link->dhcp_lease);
36
d4c52ee5
YW
37 (void) sd_dhcp_lease_get_address(link->dhcp_lease_old, &address_old);
38 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
d03073dd 39
d4c52ee5
YW
40 (void) dhcp_remove_routes(link, link->dhcp_lease_old, &address_old, false);
41 (void) dhcp_remove_router(link, link->dhcp_lease_old, &address_old, false);
854a1ccf 42 (void) dhcp_remove_dns_routes(link, link->dhcp_lease_old, &address_old, false);
d03073dd 43
d4c52ee5 44 if (!in4_addr_equal(&address_old, &address))
dd9b10c8 45 (void) dhcp_remove_address(link, link->dhcp_lease_old, &address_old, NULL);
d03073dd
YW
46
47 link->dhcp_lease_old = sd_dhcp_lease_unref(link->dhcp_lease_old);
48 link_dirty(link);
49}
50
302a796f 51static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3c9b8860
TG
52 int r;
53
54 assert(link);
6cf4a01c 55 assert(link->dhcp4_messages > 0);
3c9b8860 56
313cefa1 57 link->dhcp4_messages--;
3c9b8860 58
3ab7ed3f
YW
59 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
60 return 1;
61
1c4baffc 62 r = sd_netlink_message_get_errno(m);
dd9b10c8
YW
63 if (r == -ENETUNREACH && !link->dhcp4_route_retrying) {
64
65 /* It seems kernel does not support that the prefix route cannot be configured with
66 * route table. Let's once drop the config and reconfigure them later. */
67
5ecb131d 68 log_link_message_debug_errno(link, m, r, "Could not set DHCPv4 route, retrying later: %m");
dd9b10c8
YW
69 link->dhcp4_route_failed = true;
70 link->manager->dhcp4_prefix_root_cannot_set_table = true;
71 } else if (r < 0 && r != -EEXIST) {
5ecb131d 72 log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 route: %m");
3c9b8860 73 link_enter_failed(link);
3ab7ed3f 74 return 1;
3c9b8860
TG
75 }
76
6cf4a01c 77 if (link->dhcp4_messages == 0) {
dd9b10c8
YW
78 if (link->dhcp4_route_failed) {
79 struct in_addr address = {};
80
81 link->dhcp4_route_failed = false;
82 link->dhcp4_route_retrying = true;
83
84 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
85 (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
86 (void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
87 (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
88 (void) dhcp_remove_address(link, link->dhcp_lease, &address, dhcp_remove_address_handler);
89
90 return 1;
91 }
3c9b8860 92 link->dhcp4_configured = true;
d03073dd
YW
93 /* New address and routes are configured now. Let's release old lease. */
94 dhcp4_release_old_lease(link);
8012cd39 95 link_check_ready(link);
3c9b8860
TG
96 }
97
98 return 1;
99}
100
d6eac9bd
DW
101static int route_scope_from_address(const Route *route, const struct in_addr *self_addr) {
102 assert(route);
103 assert(self_addr);
104
7ed5420a
YW
105 if (in4_addr_is_localhost(&route->dst.in) ||
106 (!in4_addr_is_null(self_addr) && in4_addr_equal(&route->dst.in, self_addr)))
d6eac9bd
DW
107 return RT_SCOPE_HOST;
108 else if (in4_addr_is_null(&route->gw.in))
109 return RT_SCOPE_LINK;
110 else
111 return RT_SCOPE_UNIVERSE;
112}
113
de697db0
YW
114static bool link_prefixroute(Link *link) {
115 return !link->network->dhcp_route_table_set ||
116 link->network->dhcp_route_table == RT_TABLE_MAIN ||
117 link->manager->dhcp4_prefix_root_cannot_set_table;
156ddf8d
YW
118}
119
d4c52ee5
YW
120static int dhcp_route_configure(Route **route, Link *link) {
121 int r;
122
123 assert(route);
124 assert(*route);
125 assert(link);
126
127 if (set_contains(link->dhcp_routes, *route))
128 return 0;
129
130 r = route_configure(*route, link, dhcp4_route_handler);
131 if (r <= 0)
132 return r;
133
134 link->dhcp4_messages++;
135
136 r = set_put(link->dhcp_routes, *route);
137 if (r < 0)
138 return r;
139
140 TAKE_PTR(*route);
141 return 0;
142}
143
854a1ccf
YW
144static int link_set_dns_routes(Link *link, const struct in_addr *address) {
145 const struct in_addr *dns;
146 uint32_t table;
147 int i, n, r;
148
149 assert(link);
150 assert(link->dhcp_lease);
151 assert(link->network);
152
a24e12f0
YW
153 if (!link->network->dhcp_use_dns ||
154 !link->network->dhcp_routes_to_dns)
854a1ccf
YW
155 return 0;
156
157 n = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
158 if (IN_SET(n, 0, -ENODATA))
159 return 0;
160 if (n < 0)
161 return log_link_warning_errno(link, n, "DHCP error: could not get DNS servers: %m");
162
163 table = link_get_dhcp_route_table(link);
164
165 for (i = 0; i < n; i ++) {
166 _cleanup_(route_freep) Route *route = NULL;
167
168 r = route_new(&route);
169 if (r < 0)
170 return log_link_error_errno(link, r, "Could not allocate route: %m");
171
172 /* Set routes to DNS servers. */
173
174 route->family = AF_INET;
175 route->dst.in = dns[i];
176 route->dst_prefixlen = 32;
177 route->prefsrc.in = *address;
178 route->scope = RT_SCOPE_LINK;
179 route->protocol = RTPROT_DHCP;
180 route->priority = link->network->dhcp_route_metric;
181 route->table = table;
182
183 r = dhcp_route_configure(&route, link);
184 if (r < 0)
185 return log_link_error_errno(link, r, "Could not set route to DNS server: %m");
186 }
187
188 return 0;
189}
190
e723fbd7
ZJS
191static int dhcp_prefix_route_from_lease(
192 const sd_dhcp_lease *lease,
193 uint32_t table,
194 const struct in_addr *address,
195 Route **ret_route) {
196
197 Route *route;
198 struct in_addr netmask;
199 int r;
200
201 r = sd_dhcp_lease_get_netmask((sd_dhcp_lease*) lease, &netmask);
202 if (r < 0)
203 return r;
204
205 r = route_new(&route);
206 if (r < 0)
207 return r;
208
209 route->family = AF_INET;
210 route->dst.in.s_addr = address->s_addr & netmask.s_addr;
211 route->dst_prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
212 route->prefsrc.in = *address;
213 route->scope = RT_SCOPE_LINK;
214 route->protocol = RTPROT_DHCP;
215 route->table = table;
216 *ret_route = route;
217 return 0;
218}
219
3c9b8860 220static int link_set_dhcp_routes(Link *link) {
f8693fc7 221 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
8cdc46e7 222 bool classless_route = false, static_route = false;
f8862395
TH
223 const struct in_addr *router;
224 struct in_addr address;
3c9b8860 225 int r, n, i;
fc1ba79d 226 uint32_t table;
3c9b8860
TG
227
228 assert(link);
0c9b15a3
AJ
229
230 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
231 return 0;
232
233 if (!link->network) /* link went down while we configured the IP addresses? */
234 return 0;
964b26fe
SS
235
236 if (!link->network->dhcp_use_routes)
237 return 0;
3c9b8860 238
4e2ef9d9
YW
239 if (!link_has_carrier(link) && !link->network->configure_without_carrier)
240 /* During configuring addresses, the link lost its carrier. As networkd is dropping
241 * the addresses now, let's not configure the routes either. */
242 return 0;
243
c077a205 244 r = set_ensure_allocated(&link->dhcp_routes, &route_hash_ops);
d4c52ee5
YW
245 if (r < 0)
246 return log_oom();
247
248 /* Clear old entries in case the set was already allocated */
249 set_clear(link->dhcp_routes);
250
bdb9f580 251 table = link_get_dhcp_route_table(link);
fc1ba79d 252
b23aec0d
DW
253 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
254 if (r < 0)
255 return log_link_warning_errno(link, r, "DHCP error: could not get address: %m");
256
de697db0 257 if (!link_prefixroute(link)) {
156ddf8d 258 _cleanup_(route_freep) Route *prefix_route = NULL;
156ddf8d 259
e723fbd7 260 r = dhcp_prefix_route_from_lease(link->dhcp_lease, table, &address, &prefix_route);
156ddf8d 261 if (r < 0)
e723fbd7 262 return log_link_error_errno(link, r, "Could not create prefix route: %m");
156ddf8d
YW
263
264 r = dhcp_route_configure(&prefix_route, link);
265 if (r < 0)
266 return log_link_error_errno(link, r, "Could not set prefix route: %m");
267 }
268
5f04a209 269 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
599c44e6
YW
270 if (n == -ENODATA)
271 log_link_debug_errno(link, n, "DHCP: No routes received from DHCP server: %m");
272 else if (n < 0)
61cda4d7 273 log_link_debug_errno(link, n, "DHCP: could not get routes: %m");
5f04a209 274
8cdc46e7 275 for (i = 0; i < n; i++) {
3476951c
TH
276 switch (sd_dhcp_route_get_option(static_routes[i])) {
277 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
8cdc46e7 278 classless_route = true;
3476951c
TH
279 break;
280 case SD_DHCP_OPTION_STATIC_ROUTE:
8cdc46e7 281 static_route = true;
3476951c
TH
282 break;
283 }
8cdc46e7
SS
284 }
285
5f04a209 286 for (i = 0; i < n; i++) {
8e766630 287 _cleanup_(route_freep) Route *route = NULL;
5f04a209 288
8cdc46e7
SS
289 /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
290 the DHCP client MUST ignore the Static Routes option. */
3476951c
TH
291 if (classless_route &&
292 sd_dhcp_route_get_option(static_routes[i]) != SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE)
8cdc46e7
SS
293 continue;
294
5f04a209
SS
295 r = route_new(&route);
296 if (r < 0)
297 return log_link_error_errno(link, r, "Could not allocate route: %m");
298
299 route->family = AF_INET;
300 route->protocol = RTPROT_DHCP;
301 assert_se(sd_dhcp_route_get_gateway(static_routes[i], &route->gw.in) >= 0);
302 assert_se(sd_dhcp_route_get_destination(static_routes[i], &route->dst.in) >= 0);
303 assert_se(sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen) >= 0);
304 route->priority = link->network->dhcp_route_metric;
305 route->table = table;
306 route->scope = route_scope_from_address(route, &address);
ac2dce5f
DS
307 if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
308 route->prefsrc.in = address;
5f04a209 309
d4c52ee5
YW
310 if (set_contains(link->dhcp_routes, route))
311 continue;
312
313 r = dhcp_route_configure(&route, link);
5f04a209 314 if (r < 0)
d4c52ee5 315 return log_link_error_errno(link, r, "Could not set route: %m");
5f04a209
SS
316 }
317
f8862395 318 r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
825ace96
YW
319 if (IN_SET(r, 0, -ENODATA))
320 log_link_info(link, "DHCP: No gateway received from DHCP server.");
321 else if (r < 0)
444b0170 322 log_link_warning_errno(link, r, "DHCP error: could not get gateway: %m");
825ace96
YW
323 else if (in4_addr_is_null(&router[0]))
324 log_link_info(link, "DHCP: Received gateway is null.");
f6b8196f 325
5f04a209
SS
326 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
327 a Router option, the DHCP client MUST ignore the Router option. */
8cdc46e7
SS
328 if (classless_route && static_route)
329 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option and router option");
330
f8862395 331 if (r > 0 && !classless_route && !in4_addr_is_null(&router[0])) {
860e636c 332 _cleanup_(route_freep) Route *route = NULL, *route_gw = NULL;
ed9e361a
TG
333
334 r = route_new(&route_gw);
f6b8196f
LP
335 if (r < 0)
336 return log_link_error_errno(link, r, "Could not allocate route: %m");
3c9b8860
TG
337
338 /* The dhcp netmask may mask out the gateway. Add an explicit
339 * route for the gw host so that we can route no matter the
340 * netmask or existing kernel route tables. */
341 route_gw->family = AF_INET;
f8862395 342 route_gw->dst.in = router[0];
3c9b8860 343 route_gw->dst_prefixlen = 32;
2ce40956 344 route_gw->prefsrc.in = address;
3c9b8860 345 route_gw->scope = RT_SCOPE_LINK;
ed9e361a 346 route_gw->protocol = RTPROT_DHCP;
86655331 347 route_gw->priority = link->network->dhcp_route_metric;
fc1ba79d 348 route_gw->table = table;
3c9b8860 349
d4c52ee5 350 r = dhcp_route_configure(&route_gw, link);
f6b8196f 351 if (r < 0)
1590dfa4 352 return log_link_error_errno(link, r, "Could not set host route: %m");
3c9b8860 353
860e636c
YW
354 r = route_new(&route);
355 if (r < 0)
356 return log_link_error_errno(link, r, "Could not allocate route: %m");
357
3c9b8860 358 route->family = AF_INET;
f8862395 359 route->gw.in = router[0];
2ce40956 360 route->prefsrc.in = address;
860e636c 361 route->protocol = RTPROT_DHCP;
86655331 362 route->priority = link->network->dhcp_route_metric;
fc1ba79d 363 route->table = table;
3c9b8860 364
d4c52ee5 365 r = dhcp_route_configure(&route, link);
1590dfa4 366 if (r < 0)
d4c52ee5 367 return log_link_error_errno(link, r, "Could not set router: %m");
3c9b8860
TG
368 }
369
854a1ccf 370 return link_set_dns_routes(link, &address);
3c9b8860
TG
371}
372
d4c52ee5
YW
373static int dhcp_remove_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
374 _cleanup_free_ sd_dhcp_route **routes = NULL;
7fa472f9 375 uint32_t table;
d4c52ee5 376 int n, i, r;
3c9b8860
TG
377
378 assert(link);
7fa472f9 379 assert(address);
3c9b8860 380
7fa472f9
YW
381 if (!link->network->dhcp_use_routes)
382 return 0;
3c9b8860 383
d03073dd
YW
384 n = sd_dhcp_lease_get_routes(lease, &routes);
385 if (IN_SET(n, 0, -ENODATA))
7fa472f9 386 return 0;
d03073dd
YW
387 else if (n < 0)
388 return log_link_error_errno(link, n, "DHCP error: Failed to get routes: %m");
389
7fa472f9 390 table = link_get_dhcp_route_table(link);
8df8ce78 391
7fa472f9
YW
392 for (i = 0; i < n; i++) {
393 _cleanup_(route_freep) Route *route = NULL;
3c9b8860 394
7fa472f9
YW
395 r = route_new(&route);
396 if (r < 0)
397 return log_oom();
398
399 route->family = AF_INET;
400 assert_se(sd_dhcp_route_get_gateway(routes[i], &route->gw.in) >= 0);
401 assert_se(sd_dhcp_route_get_destination(routes[i], &route->dst.in) >= 0);
402 assert_se(sd_dhcp_route_get_destination_prefix_length(routes[i], &route->dst_prefixlen) >= 0);
403 route->priority = link->network->dhcp_route_metric;
404 route->table = table;
405 route->scope = route_scope_from_address(route, address);
ac2dce5f
DS
406 if (IN_SET(route->scope, RT_SCOPE_LINK, RT_SCOPE_UNIVERSE))
407 route->prefsrc.in = *address;
7fa472f9 408
d4c52ee5 409 if (!remove_all && set_contains(link->dhcp_routes, route))
d03073dd
YW
410 continue;
411
7fa472f9 412 (void) route_remove(route, link, NULL);
b5799eeb 413 }
3c9b8860 414
7fa472f9
YW
415 return n;
416}
8df8ce78 417
d4c52ee5 418static int dhcp_remove_router(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
7fa472f9
YW
419 _cleanup_(route_freep) Route *route_gw = NULL, *route = NULL;
420 const struct in_addr *router;
421 uint32_t table;
422 int r;
8df8ce78 423
7fa472f9
YW
424 assert(link);
425 assert(address);
3c9b8860 426
7fa472f9
YW
427 if (!link->network->dhcp_use_routes)
428 return 0;
3c9b8860 429
d03073dd 430 r = sd_dhcp_lease_get_router(lease, &router);
7fa472f9
YW
431 if (IN_SET(r, 0, -ENODATA)) {
432 log_link_debug(link, "DHCP: No gateway received from DHCP server.");
433 return 0;
434 } else if (r < 0)
435 return log_link_error_errno(link, r, "DHCP error: could not get gateway: %m");
436 else if (in4_addr_is_null(&router[0])) {
437 log_link_info(link, "DHCP: Received gateway is null, ignoring.");
438 return 0;
3c9b8860
TG
439 }
440
7fa472f9 441 table = link_get_dhcp_route_table(link);
3c9b8860 442
7fa472f9
YW
443 r = route_new(&route_gw);
444 if (r < 0)
445 return log_oom();
3c9b8860 446
7fa472f9
YW
447 route_gw->family = AF_INET;
448 route_gw->dst.in = router[0];
449 route_gw->dst_prefixlen = 32;
450 route_gw->prefsrc.in = *address;
451 route_gw->scope = RT_SCOPE_LINK;
452 route_gw->protocol = RTPROT_DHCP;
453 route_gw->priority = link->network->dhcp_route_metric;
454 route_gw->table = table;
a7d0ef44 455
d4c52ee5
YW
456 if (remove_all || !set_contains(link->dhcp_routes, route_gw))
457 (void) route_remove(route_gw, link, NULL);
7fa472f9
YW
458
459 r = route_new(&route);
460 if (r < 0)
461 return log_oom();
462
463 route->family = AF_INET;
464 route->gw.in = router[0];
465 route->prefsrc.in = *address;
466 route->protocol = RTPROT_DHCP;
467 route->priority = link->network->dhcp_route_metric;
468 route->table = table;
469
d4c52ee5
YW
470 if (remove_all || !set_contains(link->dhcp_routes, route))
471 (void) route_remove(route, link, NULL);
7fa472f9
YW
472
473 return 0;
474}
475
854a1ccf
YW
476static int dhcp_remove_dns_routes(Link *link, sd_dhcp_lease *lease, const struct in_addr *address, bool remove_all) {
477 const struct in_addr *dns;
478 uint32_t table;
479 int i, n, r;
480
481 assert(link);
482 assert(lease);
483 assert(link->network);
484
a24e12f0
YW
485 if (!link->network->dhcp_use_dns ||
486 !link->network->dhcp_routes_to_dns)
854a1ccf
YW
487 return 0;
488
489 n = sd_dhcp_lease_get_dns(lease, &dns);
490 if (IN_SET(n, 0, -ENODATA))
491 return 0;
492 if (n < 0)
493 return log_link_warning_errno(link, n, "DHCP error: could not get DNS servers: %m");
494
495 table = link_get_dhcp_route_table(link);
496
497 for (i = 0; i < n; i ++) {
498 _cleanup_(route_freep) Route *route = NULL;
499
500 r = route_new(&route);
501 if (r < 0)
502 return log_link_error_errno(link, r, "Could not allocate route: %m");
503
504 route->family = AF_INET;
505 route->dst.in = dns[i];
506 route->dst_prefixlen = 32;
507 route->prefsrc.in = *address;
508 route->scope = RT_SCOPE_LINK;
509 route->protocol = RTPROT_DHCP;
510 route->priority = link->network->dhcp_route_metric;
511 route->table = table;
512
513 if (!remove_all && set_contains(link->dhcp_routes, route))
514 continue;
515
516 (void) route_remove(route, link, NULL);
517 }
518
de697db0 519 if (!link_prefixroute(link)) {
156ddf8d 520 _cleanup_(route_freep) Route *prefix_route = NULL;
156ddf8d 521
e723fbd7 522 r = dhcp_prefix_route_from_lease(lease, table, address, &prefix_route);
156ddf8d 523 if (r < 0)
e723fbd7 524 return log_link_warning_errno(link, r, "Could not delete prefix route: %m");
156ddf8d
YW
525
526 if (remove_all || !set_contains(link->dhcp_routes, prefix_route))
527 (void) route_remove(prefix_route, link, NULL);
528 }
529
854a1ccf
YW
530 return 0;
531}
532
dd9b10c8
YW
533static int dhcp_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
534 int r;
535
536 assert(link);
537
538 /* This is only used when retrying to assign the address received from DHCPv4 server.
539 * See dhcp4_route_handler(). */
540
541 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
542 return 1;
543
544 r = sd_netlink_message_get_errno(m);
545 if (r < 0)
5ecb131d 546 log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
dd9b10c8
YW
547 else
548 (void) manager_rtnl_process_address(rtnl, m, link->manager);
549
550 (void) dhcp_lease_renew(link->dhcp_client, link);
551 return 1;
552}
553
554static int dhcp_remove_address(
555 Link *link, sd_dhcp_lease *lease,
556 const struct in_addr *address,
557 link_netlink_message_handler_t callback) {
558
7fa472f9
YW
559 _cleanup_(address_freep) Address *a = NULL;
560 struct in_addr netmask;
561 int r;
562
563 assert(link);
564 assert(address);
565
566 if (in4_addr_is_null(address))
567 return 0;
568
569 r = address_new(&a);
570 if (r < 0)
571 return log_oom();
572
573 a->family = AF_INET;
574 a->in_addr.in = *address;
575
d03073dd 576 if (sd_dhcp_lease_get_netmask(lease, &netmask) >= 0)
7fa472f9
YW
577 a->prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
578
dd9b10c8 579 (void) address_remove(a, link, callback);
7fa472f9
YW
580
581 return 0;
582}
583
584static int dhcp_reset_mtu(Link *link) {
585 uint16_t mtu;
586 int r;
587
588 assert(link);
589
590 if (!link->network->dhcp_use_mtu)
591 return 0;
592
593 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
594 if (r < 0)
595 return r;
596
597 if (link->original_mtu == mtu)
598 return 0;
599
600 r = link_set_mtu(link, link->original_mtu);
601 if (r < 0) {
602 log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
603 link_enter_failed(link);
604 return r;
3c9b8860
TG
605 }
606
7fa472f9
YW
607 return 0;
608}
609
610static int dhcp_reset_hostname(Link *link) {
611 const char *hostname;
612 int r;
613
614 assert(link);
615
616 if (!link->network->dhcp_use_hostname)
617 return 0;
618
619 hostname = link->network->dhcp_hostname;
620 if (!hostname)
621 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
622
623 if (!hostname)
624 return 0;
625
626 /* If a hostname was set due to the lease, then unset it now. */
627 r = manager_set_hostname(link->manager, NULL);
628 if (r < 0)
629 return log_link_error_errno(link, r, "DHCP error: Failed to reset transient hostname: %m");
630
631 return 0;
632}
633
634static int dhcp_lease_lost(Link *link) {
635 struct in_addr address = {};
636
637 assert(link);
638 assert(link->dhcp_lease);
639
f8c2e4b9 640 log_link_info(link, "DHCP lease lost");
7fa472f9
YW
641
642 link->dhcp4_configured = false;
643
644 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address);
d4c52ee5
YW
645 (void) dhcp_remove_routes(link, link->dhcp_lease, &address, true);
646 (void) dhcp_remove_router(link, link->dhcp_lease, &address, true);
854a1ccf 647 (void) dhcp_remove_dns_routes(link, link->dhcp_lease, &address, true);
dd9b10c8 648 (void) dhcp_remove_address(link, link->dhcp_lease, &address, NULL);
7fa472f9
YW
649 (void) dhcp_reset_mtu(link);
650 (void) dhcp_reset_hostname(link);
651
3c9b8860 652 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
6a3e5f6a 653 link_dirty(link);
3c9b8860
TG
654
655 return 0;
656}
657
302a796f 658static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3c9b8860
TG
659 int r;
660
661 assert(link);
662
3ab7ed3f
YW
663 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
664 return 1;
665
1c4baffc 666 r = sd_netlink_message_get_errno(m);
3c9b8860 667 if (r < 0 && r != -EEXIST) {
5ecb131d 668 log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 address");
3c9b8860 669 link_enter_failed(link);
3ab7ed3f 670 return 1;
4ff296b0
YW
671 } else if (r >= 0)
672 (void) manager_rtnl_process_address(rtnl, m, link->manager);
3c9b8860 673
1590dfa4
YW
674 r = link_set_dhcp_routes(link);
675 if (r < 0) {
676 link_enter_failed(link);
677 return 1;
678 }
3c9b8860 679
b5799eeb 680 /* Add back static routes since kernel removes while DHCPv4 address is removed from when lease expires */
4ff296b0
YW
681 r = link_request_set_routes(link);
682 if (r < 0) {
683 link_enter_failed(link);
684 return 1;
685 }
b5799eeb 686
223932c7
AH
687 if (link->dhcp4_messages == 0) {
688 link->dhcp4_configured = true;
d03073dd
YW
689 /* The new address is configured, and no route is requested.
690 * Let's drop the old lease. */
691 dhcp4_release_old_lease(link);
223932c7
AH
692 link_check_ready(link);
693 }
694
3c9b8860
TG
695 return 1;
696}
697
698static int dhcp4_update_address(Link *link,
699 struct in_addr *address,
700 struct in_addr *netmask,
701 uint32_t lifetime) {
8e766630 702 _cleanup_(address_freep) Address *addr = NULL;
3c9b8860
TG
703 unsigned prefixlen;
704 int r;
705
706 assert(address);
707 assert(netmask);
708 assert(lifetime);
709
5a941f5f 710 prefixlen = in4_addr_netmask_to_prefixlen(netmask);
3c9b8860 711
f0213e37 712 r = address_new(&addr);
3c9b8860
TG
713 if (r < 0)
714 return r;
715
716 addr->family = AF_INET;
717 addr->in_addr.in.s_addr = address->s_addr;
718 addr->cinfo.ifa_prefered = lifetime;
719 addr->cinfo.ifa_valid = lifetime;
720 addr->prefixlen = prefixlen;
721 addr->broadcast.s_addr = address->s_addr | ~netmask->s_addr;
de697db0 722 addr->prefix_route = link_prefixroute(link);
3c9b8860 723
66669078
TG
724 /* allow reusing an existing address and simply update its lifetime
725 * in case it already exists */
483d099e 726 r = address_configure(addr, link, dhcp4_address_handler, true);
3c9b8860
TG
727 if (r < 0)
728 return r;
729
730 return 0;
731}
732
733static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
734 sd_dhcp_lease *lease;
735 struct in_addr address;
736 struct in_addr netmask;
737 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
738 int r;
739
740 assert(link);
741 assert(client);
742 assert(link->network);
743
744 r = sd_dhcp_client_get_lease(client, &lease);
f6b8196f
LP
745 if (r < 0)
746 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
3c9b8860
TG
747
748 sd_dhcp_lease_unref(link->dhcp_lease);
749 link->dhcp4_configured = false;
e6b18ffa 750 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 751 link_dirty(link);
3c9b8860
TG
752
753 r = sd_dhcp_lease_get_address(lease, &address);
f6b8196f
LP
754 if (r < 0)
755 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
3c9b8860
TG
756
757 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f6b8196f
LP
758 if (r < 0)
759 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
3c9b8860 760
7da377ef 761 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
f6b8196f
LP
762 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
763 if (r < 0)
764 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
3c9b8860
TG
765 }
766
767 r = dhcp4_update_address(link, &address, &netmask, lifetime);
a2f68490
YW
768 if (r < 0)
769 return log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
770
771 return 0;
772}
773
774static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
f8862395 775 const struct in_addr *router;
3c9b8860
TG
776 sd_dhcp_lease *lease;
777 struct in_addr address;
778 struct in_addr netmask;
3c9b8860
TG
779 unsigned prefixlen;
780 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
781 int r;
782
783 assert(client);
784 assert(link);
785
a20c909c
YW
786 link->dhcp4_configured = false;
787
3c9b8860 788 r = sd_dhcp_client_get_lease(client, &lease);
f2341e0a 789 if (r < 0)
f6b8196f 790 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
3c9b8860
TG
791
792 r = sd_dhcp_lease_get_address(lease, &address);
f2341e0a 793 if (r < 0)
f6b8196f 794 return log_link_error_errno(link, r, "DHCP error: No address: %m");
3c9b8860
TG
795
796 r = sd_dhcp_lease_get_netmask(lease, &netmask);
f2341e0a 797 if (r < 0)
f6b8196f 798 return log_link_error_errno(link, r, "DHCP error: No netmask: %m");
3c9b8860 799
5a941f5f 800 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
3c9b8860 801
448aaf9f
YW
802 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
803 r = sd_dhcp_lease_get_lifetime(lease, &lifetime);
804 if (r < 0)
805 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
806 }
807
f8862395 808 r = sd_dhcp_lease_get_router(lease, &router);
397d15fd 809 if (r < 0 && r != -ENODATA)
f6b8196f 810 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
3c9b8860 811
f8862395 812 if (r > 0 && !in4_addr_is_null(&router[0]))
f2341e0a
LP
813 log_struct(LOG_INFO,
814 LOG_LINK_INTERFACE(link),
815 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u via %u.%u.%u.%u",
816 ADDRESS_FMT_VAL(address),
817 prefixlen,
f8862395 818 ADDRESS_FMT_VAL(router[0])),
f2341e0a
LP
819 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
820 "PREFIXLEN=%u", prefixlen,
f8862395 821 "GATEWAY=%u.%u.%u.%u", ADDRESS_FMT_VAL(router[0]));
3c9b8860 822 else
f2341e0a
LP
823 log_struct(LOG_INFO,
824 LOG_LINK_INTERFACE(link),
825 LOG_LINK_MESSAGE(link, "DHCPv4 address %u.%u.%u.%u/%u",
826 ADDRESS_FMT_VAL(address),
827 prefixlen),
828 "ADDRESS=%u.%u.%u.%u", ADDRESS_FMT_VAL(address),
a1230ff9 829 "PREFIXLEN=%u", prefixlen);
3c9b8860 830
e6b18ffa 831 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 832 link_dirty(link);
3c9b8860 833
27cb34f5 834 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
835 uint16_t mtu;
836
837 r = sd_dhcp_lease_get_mtu(lease, &mtu);
838 if (r >= 0) {
933c70a0 839 r = link_set_mtu(link, mtu);
3c9b8860 840 if (r < 0)
f2341e0a 841 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
3c9b8860
TG
842 }
843 }
844
27cb34f5 845 if (link->network->dhcp_use_hostname) {
2de2abad
LB
846 const char *dhcpname = NULL;
847 _cleanup_free_ char *hostname = NULL;
3c9b8860 848
27cb34f5 849 if (link->network->dhcp_hostname)
2de2abad 850 dhcpname = link->network->dhcp_hostname;
dce391e7 851 else
2de2abad
LB
852 (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
853
854 if (dhcpname) {
855 r = shorten_overlong(dhcpname, &hostname);
856 if (r < 0)
857 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
858 if (r == 1)
5238e957 859 log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
2de2abad 860 }
a7d0ef44 861
dce391e7 862 if (hostname) {
59eb33e0 863 r = manager_set_hostname(link->manager, hostname);
3c9b8860 864 if (r < 0)
f2341e0a 865 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
3c9b8860
TG
866 }
867 }
868
27cb34f5 869 if (link->network->dhcp_use_timezone) {
21b80ad1
LP
870 const char *tz = NULL;
871
872 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
873
874 if (tz) {
59eb33e0 875 r = manager_set_timezone(link->manager, tz);
21b80ad1
LP
876 if (r < 0)
877 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
878 }
879 }
880
3c9b8860 881 r = dhcp4_update_address(link, &address, &netmask, lifetime);
a2f68490
YW
882 if (r < 0)
883 return log_link_warning_errno(link, r, "Could not update IP address: %m");
3c9b8860
TG
884
885 return 0;
886}
8bc17bb3 887
d03073dd
YW
888static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
889 int r;
890
891 link->dhcp_lease_old = TAKE_PTR(link->dhcp_lease);
892
893 /* On ip address change, to keep the connectability, we would like to assign new address and
894 * routes, and then release old lease. There are two possible success paths:
895 *
896 * 1. new address and routes are configured.
897 * -> handled by dhcp_release_old_lease() in dhcp4_route_handler().
898 * 2. new address is configured and no route is requested.
899 * -> handled by dhcp_release_old_lease() in dhcp4_address_handler().
900 *
901 * On error in assigning new address and routes, then the link always enters to the failed
902 * state. And link_enter_failed() leads to the DHCP client to be stopped. So,
903 * dhcp_release_old_lease() will be also called by link_stop_clients().
904 */
905
906 r = dhcp_lease_acquired(client, link);
907 if (r < 0) {
908 /* If it fails, then the new address is not configured yet.
909 * So, let's simply drop the old lease. */
910 sd_dhcp_lease_unref(link->dhcp_lease);
911 link->dhcp_lease = TAKE_PTR(link->dhcp_lease_old);
912 (void) dhcp_lease_lost(link);
913 return r;
914 }
915
916 return 0;
917}
918
727b5734
SS
919static int dhcp_server_is_black_listed(Link *link, sd_dhcp_client *client) {
920 sd_dhcp_lease *lease;
921 struct in_addr addr;
922 int r;
923
924 assert(link);
925 assert(link->network);
926 assert(client);
927
928 r = sd_dhcp_client_get_lease(client, &lease);
929 if (r < 0)
930 return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
931
932 r = sd_dhcp_lease_get_server_identifier(lease, &addr);
933 if (r < 0)
934 return log_link_debug_errno(link, r, "Failed to get DHCP server ip address: %m");
935
936 if (set_contains(link->network->dhcp_black_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
937 log_struct(LOG_DEBUG,
938 LOG_LINK_INTERFACE(link),
939 LOG_LINK_MESSAGE(link, "DHCPv4 ip '%u.%u.%u.%u' found in black listed ip addresses, ignoring offer",
940 ADDRESS_FMT_VAL(addr)));
941 return true;
942 }
943
944 return false;
945}
946
947static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
3c9b8860 948 Link *link = userdata;
86e2be7b 949 int r;
3c9b8860
TG
950
951 assert(link);
952 assert(link->network);
953 assert(link->manager);
954
955 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
727b5734 956 return 0;
3c9b8860
TG
957
958 switch (event) {
03748142 959 case SD_DHCP_CLIENT_EVENT_STOP:
8bc17bb3 960
910feb78 961 if (link_ipv4ll_enabled(link, ADDRESS_FAMILY_FALLBACK_IPV4)) {
8bc17bb3
SS
962 assert(link->ipv4ll);
963
964 log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
965
966 r = sd_ipv4ll_start(link->ipv4ll);
727b5734
SS
967 if (r < 0)
968 return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
8bc17bb3
SS
969 }
970
7da377ef 971 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
efdb62df
YW
972 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
973 return 0;
974 }
975
efdb62df 976 if (link->dhcp_lease) {
8bea7e70
ZJS
977 if (link->network->dhcp_send_release)
978 (void) sd_dhcp_client_send_release(client);
979
efdb62df
YW
980 r = dhcp_lease_lost(link);
981 if (r < 0) {
982 link_enter_failed(link);
983 return r;
984 }
985 }
986
987 break;
8bc17bb3 988 case SD_DHCP_CLIENT_EVENT_EXPIRED:
7da377ef 989 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
efdb62df 990 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
727b5734 991 return 0;
3c9b8860
TG
992 }
993
994 if (link->dhcp_lease) {
995 r = dhcp_lease_lost(link);
996 if (r < 0) {
997 link_enter_failed(link);
727b5734 998 return r;
3c9b8860
TG
999 }
1000 }
1001
d03073dd
YW
1002 break;
1003 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
1004 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
1005 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
1006 return 0;
1007 }
1008
1009 r = dhcp_lease_ip_change(client, link);
1010 if (r < 0) {
1011 link_enter_failed(link);
1012 return r;
3c9b8860
TG
1013 }
1014
1015 break;
03748142 1016 case SD_DHCP_CLIENT_EVENT_RENEW:
3c9b8860
TG
1017 r = dhcp_lease_renew(client, link);
1018 if (r < 0) {
1019 link_enter_failed(link);
727b5734 1020 return r;
3c9b8860
TG
1021 }
1022 break;
03748142 1023 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
3c9b8860
TG
1024 r = dhcp_lease_acquired(client, link);
1025 if (r < 0) {
1026 link_enter_failed(link);
727b5734 1027 return r;
3c9b8860
TG
1028 }
1029 break;
727b5734
SS
1030 case SD_DHCP_CLIENT_EVENT_SELECTING:
1031 r = dhcp_server_is_black_listed(link, client);
1032 if (r < 0)
1033 return r;
1034 if (r != 0)
1035 return -ENOMSG;
1036 break;
3c9b8860
TG
1037 default:
1038 if (event < 0)
f6b8196f 1039 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
3c9b8860 1040 else
f6b8196f 1041 log_link_warning(link, "DHCP unknown event: %i", event);
3c9b8860
TG
1042 break;
1043 }
1044
727b5734 1045 return 0;
3c9b8860
TG
1046}
1047
7192bb81
LP
1048static int dhcp4_set_hostname(Link *link) {
1049 _cleanup_free_ char *hostname = NULL;
1050 const char *hn;
1051 int r;
1052
1053 assert(link);
1054
1055 if (!link->network->dhcp_send_hostname)
1056 hn = NULL;
1057 else if (link->network->dhcp_hostname)
1058 hn = link->network->dhcp_hostname;
1059 else {
1060 r = gethostname_strict(&hostname);
1061 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
1062 return r;
1063
1064 hn = hostname;
1065 }
1066
a8494759
YW
1067 r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
1068 if (r == -EINVAL && hostname)
1069 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
1070 log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
1071 else if (r < 0)
1072 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
1073
1074 return 0;
7192bb81
LP
1075}
1076
64b21ece 1077static bool promote_secondaries_enabled(const char *ifname) {
3f550c31
HV
1078 _cleanup_free_ char *promote_secondaries_sysctl = NULL;
1079 char *promote_secondaries_path;
64b21ece
MV
1080 int r;
1081
1082 promote_secondaries_path = strjoina("net/ipv4/conf/", ifname, "/promote_secondaries");
1083 r = sysctl_read(promote_secondaries_path, &promote_secondaries_sysctl);
1084 if (r < 0) {
1085 log_debug_errno(r, "Cannot read sysctl %s", promote_secondaries_path);
1086 return false;
1087 }
1088
1089 truncate_nl(promote_secondaries_sysctl);
1090 r = parse_boolean(promote_secondaries_sysctl);
1091 if (r < 0)
1092 log_warning_errno(r, "Cannot parse sysctl %s with content %s as boolean", promote_secondaries_path, promote_secondaries_sysctl);
1093 return r > 0;
1094}
1095
1096/* dhcp4_set_promote_secondaries will ensure this interface has
1097 * the "promote_secondaries" option in the kernel set. If this sysctl
1098 * is not set DHCP will work only as long as the IP address does not
1099 * changes between leases. The kernel will remove all secondary IP
1100 * addresses of an interface otherwise. The way systemd-network works
1101 * is that the new IP of a lease is added as a secondary IP and when
1102 * the primary one expires it relies on the kernel to promote the
1103 * secondary IP. See also https://github.com/systemd/systemd/issues/7163
1104 */
1105int dhcp4_set_promote_secondaries(Link *link) {
1106 int r;
1107
1108 assert(link);
1109 assert(link->network);
1110 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
1111
1112 /* check if the kernel has promote_secondaries enabled for our
1113 * interface. If it is not globally enabled or enabled for the
1114 * specific interface we must either enable it.
1115 */
8e1a7253 1116 if (!(promote_secondaries_enabled("all") || promote_secondaries_enabled(link->ifname))) {
64b21ece
MV
1117 char *promote_secondaries_path = NULL;
1118
1119 log_link_debug(link, "promote_secondaries is unset, setting it");
1120 promote_secondaries_path = strjoina("net/ipv4/conf/", link->ifname, "/promote_secondaries");
1121 r = sysctl_write(promote_secondaries_path, "1");
1122 if (r < 0)
1123 log_link_warning_errno(link, r, "cannot set sysctl %s to 1", promote_secondaries_path);
1124 return r > 0;
1125 }
1126
1127 return 0;
1128}
1129
fff1f40c
YW
1130int dhcp4_set_client_identifier(Link *link) {
1131 int r;
1132
1133 assert(link);
1134 assert(link->network);
1135 assert(link->dhcp_client);
1136
1137 switch (link->network->dhcp_client_identifier) {
1138 case DHCP_CLIENT_ID_DUID: {
0cf7c3fd 1139 /* If configured, apply user specified DUID and IAID */
fff1f40c
YW
1140 const DUID *duid = link_get_duid(link);
1141
0cf7c3fd
YW
1142 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
1143 r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
8217ed5e 1144 link->network->iaid_set,
0cf7c3fd
YW
1145 link->network->iaid,
1146 duid->llt_time);
1147 else
1148 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
8217ed5e 1149 link->network->iaid_set,
0cf7c3fd
YW
1150 link->network->iaid,
1151 duid->type,
1152 duid->raw_data_len > 0 ? duid->raw_data : NULL,
1153 duid->raw_data_len);
fff1f40c 1154 if (r < 0)
0cf7c3fd 1155 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
fff1f40c
YW
1156 break;
1157 }
1158 case DHCP_CLIENT_ID_DUID_ONLY: {
1159 /* If configured, apply user specified DUID */
1160 const DUID *duid = link_get_duid(link);
1161
0cf7c3fd
YW
1162 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
1163 r = sd_dhcp_client_set_duid_llt(link->dhcp_client,
89b3fa66 1164 duid->llt_time);
0cf7c3fd
YW
1165 else
1166 r = sd_dhcp_client_set_duid(link->dhcp_client,
1167 duid->type,
1168 duid->raw_data_len > 0 ? duid->raw_data : NULL,
1169 duid->raw_data_len);
fff1f40c
YW
1170 if (r < 0)
1171 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
1172 break;
1173 }
1174 case DHCP_CLIENT_ID_MAC:
1175 r = sd_dhcp_client_set_client_id(link->dhcp_client,
1176 ARPHRD_ETHER,
1177 (const uint8_t *) &link->mac,
1178 sizeof(link->mac));
1179 if (r < 0)
1180 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
1181 break;
1182 default:
1183 assert_not_reached("Unknown client identifier type.");
1184 }
1185
1186 return 0;
1187}
1188
3c9b8860 1189int dhcp4_configure(Link *link) {
cb29c156 1190 sd_dhcp_option *send_option;
5bc945be
SS
1191 void *request_options;
1192 Iterator i;
3c9b8860
TG
1193 int r;
1194
1195 assert(link);
1196 assert(link->network);
e0ee46f2 1197 assert(link->network->dhcp & ADDRESS_FAMILY_IPV4);
3c9b8860 1198
0bc70f1d 1199 if (!link->dhcp_client) {
db3d2358 1200 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
1f6860d9
YW
1201 if (r == -ENOMEM)
1202 return log_oom();
0bc70f1d 1203 if (r < 0)
1f6860d9 1204 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to create DHCP4 client: %m");
0bc70f1d 1205 }
3c9b8860
TG
1206
1207 r = sd_dhcp_client_attach_event(link->dhcp_client, NULL, 0);
1208 if (r < 0)
1f6860d9 1209 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to attach event: %m");
3c9b8860 1210
76253e73
DW
1211 r = sd_dhcp_client_set_mac(link->dhcp_client,
1212 (const uint8_t *) &link->mac,
1213 sizeof (link->mac), ARPHRD_ETHER);
3c9b8860 1214 if (r < 0)
1f6860d9 1215 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
3c9b8860 1216
2f8e7633 1217 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
3c9b8860 1218 if (r < 0)
1f6860d9 1219 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
3c9b8860
TG
1220
1221 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
1222 if (r < 0)
1f6860d9 1223 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
3c9b8860
TG
1224
1225 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client,
1226 link->network->dhcp_broadcast);
1227 if (r < 0)
1f6860d9 1228 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
3c9b8860
TG
1229
1230 if (link->mtu) {
1231 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
1232 if (r < 0)
1f6860d9 1233 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
3c9b8860
TG
1234 }
1235
27cb34f5 1236 if (link->network->dhcp_use_mtu) {
39745a5a 1237 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 1238 SD_DHCP_OPTION_INTERFACE_MTU);
39745a5a 1239 if (r < 0)
1f6860d9 1240 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
3c9b8860
TG
1241 }
1242
5e77a146 1243 /* NOTE: even if this variable is called "use", it also "sends" PRL
1244 * options, maybe there should be a different configuration variable
1245 * to send or not route options?. */
28522b0d 1246 /* NOTE: when using Anonymize=yes, routes PRL options are sent
1247 * by default, so they don't need to be added here. */
5e77a146 1248 if (link->network->dhcp_use_routes && !link->network->dhcp_anonymize) {
3c9b8860 1249 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 1250 SD_DHCP_OPTION_STATIC_ROUTE);
3c9b8860 1251 if (r < 0)
1f6860d9
YW
1252 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
1253
3c9b8860 1254 r = sd_dhcp_client_set_request_option(link->dhcp_client,
22805d92 1255 SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
7d6884b6 1256 if (r < 0)
1f6860d9 1257 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
3c9b8860
TG
1258 }
1259
150d3b8e
YW
1260 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO && !link->network->dhcp_anonymize) {
1261 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
1262 if (r < 0)
1263 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
1264 }
1265
ead36ce6 1266 if (link->network->dhcp_use_ntp) {
1267 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
1268 if (r < 0)
1f6860d9 1269 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
ead36ce6 1270 }
4b7b5abb 1271
299d578f
SS
1272 if (link->network->dhcp_use_sip) {
1273 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
1274 if (r < 0)
1275 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
1276 }
1277
89573b37 1278 if (link->network->dhcp_use_timezone) {
1279 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
1280 if (r < 0)
1f6860d9 1281 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
89573b37 1282 }
8eb9058d 1283
5bc945be
SS
1284 SET_FOREACH(request_options, link->network->dhcp_request_options, i) {
1285 uint32_t option = PTR_TO_UINT32(request_options);
1286
1287 r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
1288 if (r == -EEXIST) {
1289 log_link_debug(link, "DHCP4 CLIENT: Failed to set request flag for '%u' already exists, ignoring.", option);
1290 continue;
1291 }
1292
1293 if (r < 0)
1294 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
1295 }
1296
0e96961d 1297 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options, i) {
cb29c156
SS
1298 r = sd_dhcp_client_set_dhcp_option(link->dhcp_client, send_option);
1299 if (r < 0)
1300 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
1301 }
1302
7192bb81
LP
1303 r = dhcp4_set_hostname(link);
1304 if (r < 0)
a8494759 1305 return r;
3c9b8860
TG
1306
1307 if (link->network->dhcp_vendor_class_identifier) {
1308 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
1309 link->network->dhcp_vendor_class_identifier);
1310 if (r < 0)
1f6860d9 1311 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
3c9b8860
TG
1312 }
1313
af1c0de0
SS
1314 if (link->network->dhcp_user_class) {
1315 r = sd_dhcp_client_set_user_class(link->dhcp_client, (const char **) link->network->dhcp_user_class);
1316 if (r < 0)
1f6860d9 1317 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
af1c0de0
SS
1318 }
1319
9faed222
SS
1320 if (link->network->dhcp_client_port) {
1321 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
1322 if (r < 0)
1f6860d9 1323 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
9faed222
SS
1324 }
1325
715cedfb
SS
1326 if (link->network->dhcp_max_attempts > 0) {
1327 r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
1328 if (r < 0)
1329 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
1330 }
1331
afe42aef
SC
1332 if (link->network->ip_service_type > 0) {
1333 r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->ip_service_type);
1334 if (r < 0)
1335 return log_link_error_errno(link, r, "DHCP4 CLIENT: Failed to set ip service type: %m");
1336 }
1337 return dhcp4_set_client_identifier(link);
3c9b8860 1338}
ca5ad760
YW
1339
1340int config_parse_dhcp_max_attempts(
1341 const char *unit,
1342 const char *filename,
1343 unsigned line,
1344 const char *section,
1345 unsigned section_line,
1346 const char *lvalue,
1347 int ltype,
1348 const char *rvalue,
1349 void *data,
1350 void *userdata) {
1351
1352 Network *network = data;
1353 uint64_t a;
1354 int r;
1355
1356 assert(network);
1357 assert(lvalue);
1358 assert(rvalue);
1359
1360 if (isempty(rvalue)) {
1361 network->dhcp_max_attempts = 0;
1362 return 0;
1363 }
1364
1365 if (streq(rvalue, "infinity")) {
1366 network->dhcp_max_attempts = (uint64_t) -1;
1367 return 0;
1368 }
1369
1370 r = safe_atou64(rvalue, &a);
1371 if (r < 0) {
1372 log_syntax(unit, LOG_ERR, filename, line, r,
1373 "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
1374 return 0;
1375 }
1376
1377 if (a == 0) {
1378 log_syntax(unit, LOG_ERR, filename, line, 0,
1379 "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
1380 return 0;
1381 }
1382
1383 network->dhcp_max_attempts = a;
1384
1385 return 0;
1386}
1387
1388int config_parse_dhcp_black_listed_ip_address(
1389 const char *unit,
1390 const char *filename,
1391 unsigned line,
1392 const char *section,
1393 unsigned section_line,
1394 const char *lvalue,
1395 int ltype,
1396 const char *rvalue,
1397 void *data,
1398 void *userdata) {
1399
1400 Network *network = data;
1401 const char *p;
1402 int r;
1403
1404 assert(filename);
1405 assert(lvalue);
1406 assert(rvalue);
1407 assert(data);
1408
1409 if (isempty(rvalue)) {
1410 network->dhcp_black_listed_ip = set_free(network->dhcp_black_listed_ip);
1411 return 0;
1412 }
1413
1414 for (p = rvalue;;) {
1415 _cleanup_free_ char *n = NULL;
1416 union in_addr_union ip;
1417
1418 r = extract_first_word(&p, &n, NULL, 0);
1419 if (r < 0) {
1420 log_syntax(unit, LOG_ERR, filename, line, r,
1421 "Failed to parse DHCP black listed ip address, ignoring assignment: %s",
1422 rvalue);
1423 return 0;
1424 }
1425 if (r == 0)
1426 return 0;
1427
1428 r = in_addr_from_string(AF_INET, n, &ip);
1429 if (r < 0) {
1430 log_syntax(unit, LOG_ERR, filename, line, r,
1431 "DHCP black listed ip address is invalid, ignoring assignment: %s", n);
1432 continue;
1433 }
1434
1435 r = set_ensure_allocated(&network->dhcp_black_listed_ip, NULL);
1436 if (r < 0)
1437 return log_oom();
1438
1439 r = set_put(network->dhcp_black_listed_ip, UINT32_TO_PTR(ip.in.s_addr));
1440 if (r < 0)
1441 log_syntax(unit, LOG_ERR, filename, line, r,
1442 "Failed to store DHCP black listed ip address '%s', ignoring assignment: %m", n);
1443 }
1444
1445 return 0;
1446}
1447
1448int config_parse_dhcp_user_class(
1449 const char *unit,
1450 const char *filename,
1451 unsigned line,
1452 const char *section,
1453 unsigned section_line,
1454 const char *lvalue,
1455 int ltype,
1456 const char *rvalue,
1457 void *data,
1458 void *userdata) {
1459
1460 char ***l = data;
1461 int r;
1462
1463 assert(l);
1464 assert(lvalue);
1465 assert(rvalue);
1466
1467 if (isempty(rvalue)) {
1468 *l = strv_free(*l);
1469 return 0;
1470 }
1471
1472 for (;;) {
1473 _cleanup_free_ char *w = NULL;
1474
1475 r = extract_first_word(&rvalue, &w, NULL, 0);
1476 if (r == -ENOMEM)
1477 return log_oom();
1478 if (r < 0) {
1479 log_syntax(unit, LOG_ERR, filename, line, r,
1480 "Failed to split user classes option, ignoring: %s", rvalue);
1481 break;
1482 }
1483 if (r == 0)
1484 break;
1485
1486 if (strlen(w) > 255) {
1487 log_syntax(unit, LOG_ERR, filename, line, 0,
1488 "%s length is not in the range 1-255, ignoring.", w);
1489 continue;
1490 }
1491
1492 r = strv_push(l, w);
1493 if (r < 0)
1494 return log_oom();
1495
1496 w = NULL;
1497 }
1498
1499 return 0;
1500}
1501
5bc945be
SS
1502int config_parse_dhcp_request_options(
1503 const char *unit,
1504 const char *filename,
1505 unsigned line,
1506 const char *section,
1507 unsigned section_line,
1508 const char *lvalue,
1509 int ltype,
1510 const char *rvalue,
1511 void *data,
1512 void *userdata) {
1513
1514 Network *network = data;
1515 const char *p;
1516 int r;
1517
1518 assert(filename);
1519 assert(lvalue);
1520 assert(rvalue);
1521 assert(data);
1522
1523 if (isempty(rvalue)) {
1524 network->dhcp_request_options = set_free(network->dhcp_request_options);
1525 return 0;
1526 }
1527
1528 for (p = rvalue;;) {
1529 _cleanup_free_ char *n = NULL;
1530 uint32_t i;
1531
1532 r = extract_first_word(&p, &n, NULL, 0);
1533 if (r < 0) {
1534 log_syntax(unit, LOG_ERR, filename, line, r,
1535 "Failed to parse DHCP request option, ignoring assignment: %s",
1536 rvalue);
1537 return 0;
1538 }
1539 if (r == 0)
1540 return 0;
1541
1542 r = safe_atou32(n, &i);
1543 if (r < 0) {
1544 log_syntax(unit, LOG_ERR, filename, line, r,
1545 "DHCP request option is invalid, ignoring assignment: %s", n);
1546 continue;
1547 }
1548
1549 if (i < 1 || i >= 255) {
1550 log_syntax(unit, LOG_ERR, filename, line, r,
1551 "DHCP request option is invalid, valid range is 1-254, ignoring assignment: %s", n);
1552 continue;
1553 }
1554
1555 r = set_ensure_allocated(&network->dhcp_request_options, NULL);
1556 if (r < 0)
1557 return log_oom();
1558
1559 r = set_put(network->dhcp_request_options, UINT32_TO_PTR(i));
1560 if (r < 0)
1561 log_syntax(unit, LOG_ERR, filename, line, r,
1562 "Failed to store DHCP request option '%s', ignoring assignment: %m", n);
1563 }
1564
1565 return 0;
1566}
1567
ca5ad760
YW
1568static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
1569 [DHCP_CLIENT_ID_MAC] = "mac",
1570 [DHCP_CLIENT_ID_DUID] = "duid",
1571 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
1572};
1573
1574DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
1575DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
1576 "Failed to parse client identifier type");