]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp4.c
network: dhcp4: set gateway for route to DNS server if it is not in the same network
[thirdparty/systemd.git] / src / network / networkd-dhcp4.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
3c9b8860 2
9aa5d8ba 3#include <netinet/in.h>
a75b2117 4#include <netinet/ip.h>
3c9b8860 5#include <linux/if.h>
8f815e8b 6#include <linux/if_arp.h>
3c9b8860 7
7b8d23a9 8#include "escape.h"
b5efdb8a 9#include "alloc-util.h"
cb29c156 10#include "dhcp-client-internal.h"
e2054217 11#include "hostname-setup.h"
958b66ea 12#include "hostname-util.h"
64b21ece 13#include "parse-util.h"
3c9b8860 14#include "network-internal.h"
093e3533 15#include "networkd-address.h"
ca5ad760 16#include "networkd-dhcp4.h"
23f53b99
TG
17#include "networkd-link.h"
18#include "networkd-manager.h"
19#include "networkd-network.h"
3b5a4fc6 20#include "networkd-state-file.h"
ca5ad760 21#include "string-table.h"
7e19cc54 22#include "strv.h"
64b21ece 23#include "sysctl-util.h"
7b8d23a9 24#include "web-util.h"
3c9b8860 25
6906794d
YW
26static int dhcp4_update_address(Link *link, bool announce);
27static int dhcp4_remove_all(Link *link);
d03073dd 28
ae7ea5a7
YW
29void network_adjust_dhcp4(Network *network) {
30 assert(network);
31
32 if (!FLAGS_SET(network->dhcp, ADDRESS_FAMILY_IPV4))
33 return;
34
35 if (network->dhcp_use_gateway < 0)
36 network->dhcp_use_gateway = network->dhcp_use_routes;
37
f90635f1
YW
38 /* RFC7844 section 3.: MAY contain the Client Identifier option
39 * Section 3.5: clients MUST use client identifiers based solely on the link-layer address
40 * NOTE: Using MAC, as it does not reveal extra information, and some servers might not answer
41 * if this option is not sent */
42 if (network->dhcp_anonymize &&
43 network->dhcp_client_identifier >= 0 &&
44 network->dhcp_client_identifier != DHCP_CLIENT_ID_MAC) {
45 log_warning("%s: ClientIdentifier= is set, although Anonymize=yes. Using ClientIdentifier=mac.",
46 network->filename);
ae7ea5a7 47 network->dhcp_client_identifier = DHCP_CLIENT_ID_MAC;
ae7ea5a7 48 }
f90635f1
YW
49
50 if (network->dhcp_client_identifier < 0)
51 network->dhcp_client_identifier = network->dhcp_anonymize ? DHCP_CLIENT_ID_MAC : DHCP_CLIENT_ID_DUID;
ae7ea5a7
YW
52}
53
c45fdad6 54static int dhcp4_release_old_lease(Link *link) {
6e537f62 55 Route *route;
6e537f62 56 int k, r = 0;
d03073dd 57
6e537f62 58 assert(link);
d03073dd 59
6e537f62
YW
60 if (!link->dhcp_address_old && set_isempty(link->dhcp_routes_old))
61 return 0;
d03073dd 62
6e537f62 63 log_link_debug(link, "Removing old DHCPv4 address and routes.");
d03073dd 64
90e74a66 65 SET_FOREACH(route, link->dhcp_routes_old) {
ad208fac 66 k = route_remove(route, NULL, link, NULL);
6e537f62
YW
67 if (k < 0)
68 r = k;
69 }
70
71 if (link->dhcp_address_old) {
72 k = address_remove(link->dhcp_address_old, link, NULL);
73 if (k < 0)
74 r = k;
75 }
76
77 return r;
d03073dd
YW
78}
79
c1d3fa29 80static void dhcp4_check_ready(Link *link) {
6e537f62
YW
81 int r;
82
153cf041
YW
83 if (link->network->dhcp_send_decline && !link->dhcp4_address_bind)
84 return;
85
86 if (link->dhcp4_messages > 0)
87 return;
88
89 link->dhcp4_configured = true;
6e537f62 90
153cf041 91 /* New address and routes are configured now. Let's release old lease. */
c45fdad6 92 r = dhcp4_release_old_lease(link);
6e537f62
YW
93 if (r < 0) {
94 link_enter_failed(link);
95 return;
96 }
97
8ccae2dd
YW
98 r = sd_ipv4ll_stop(link->ipv4ll);
99 if (r < 0)
100 log_link_warning_errno(link, r, "Failed to drop IPv4 link-local address, ignoring: %m");
101
153cf041 102 link_check_ready(link);
c1d3fa29
YW
103}
104
302a796f 105static int dhcp4_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3c9b8860
TG
106 int r;
107
108 assert(link);
6cf4a01c 109 assert(link->dhcp4_messages > 0);
3c9b8860 110
313cefa1 111 link->dhcp4_messages--;
3c9b8860 112
3ab7ed3f
YW
113 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
114 return 1;
115
1c4baffc 116 r = sd_netlink_message_get_errno(m);
dd9b10c8
YW
117 if (r == -ENETUNREACH && !link->dhcp4_route_retrying) {
118
119 /* It seems kernel does not support that the prefix route cannot be configured with
120 * route table. Let's once drop the config and reconfigure them later. */
121
81eb5bc5 122 log_link_message_debug_errno(link, m, r, "Could not set DHCPv4 route, retrying later");
dd9b10c8
YW
123 link->dhcp4_route_failed = true;
124 link->manager->dhcp4_prefix_root_cannot_set_table = true;
125 } else if (r < 0 && r != -EEXIST) {
81eb5bc5 126 log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 route");
3c9b8860 127 link_enter_failed(link);
3ab7ed3f 128 return 1;
3c9b8860
TG
129 }
130
153cf041
YW
131 if (link->dhcp4_messages == 0 && link->dhcp4_route_failed) {
132 link->dhcp4_route_failed = false;
133 link->dhcp4_route_retrying = true;
dd9b10c8 134
153cf041
YW
135 r = dhcp4_remove_all(link);
136 if (r < 0)
137 link_enter_failed(link);
138 return 1;
3c9b8860
TG
139 }
140
153cf041
YW
141 dhcp4_check_ready(link);
142
3c9b8860
TG
143 return 1;
144}
145
6e537f62
YW
146static int dhcp_route_configure(Route *route, Link *link) {
147 Route *ret;
d4c52ee5
YW
148 int r;
149
150 assert(route);
d4c52ee5
YW
151 assert(link);
152
6e537f62
YW
153 r = route_configure(route, link, dhcp4_route_handler, &ret);
154 if (r < 0)
155 return log_link_error_errno(link, r, "Failed to set DHCPv4 route: %m");
d4c52ee5
YW
156
157 link->dhcp4_messages++;
158
6e537f62 159 r = set_ensure_put(&link->dhcp_routes, &route_hash_ops, ret);
d4c52ee5 160 if (r < 0)
6e537f62
YW
161 return log_link_error_errno(link, r, "Failed to store DHCPv4 route: %m");
162
163 (void) set_remove(link->dhcp_routes_old, ret);
d4c52ee5 164
d4c52ee5
YW
165 return 0;
166}
167
c0fef8f3
YW
168static bool link_prefixroute(Link *link) {
169 return !link->network->dhcp_route_table_set ||
170 link->network->dhcp_route_table == RT_TABLE_MAIN ||
171 link->manager->dhcp4_prefix_root_cannot_set_table;
172}
e723fbd7 173
c0fef8f3
YW
174static int link_set_dhcp_prefix_route(Link *link) {
175 _cleanup_(route_freep) Route *route = NULL;
176 struct in_addr address, netmask;
e723fbd7
ZJS
177 int r;
178
c0fef8f3
YW
179 assert(link);
180 assert(link->dhcp_lease);
181
182 if (link_prefixroute(link))
183 /* When true, the route will be created by kernel. See dhcp4_update_address(). */
184 return 0;
185
186 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
187 if (r < 0)
188 return r;
189
190 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
e723fbd7
ZJS
191 if (r < 0)
192 return r;
193
194 r = route_new(&route);
195 if (r < 0)
196 return r;
197
198 route->family = AF_INET;
c0fef8f3 199 route->dst.in.s_addr = address.s_addr & netmask.s_addr;
e723fbd7 200 route->dst_prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
c0fef8f3 201 route->prefsrc.in = address;
e723fbd7
ZJS
202 route->scope = RT_SCOPE_LINK;
203 route->protocol = RTPROT_DHCP;
c0fef8f3 204 route->table = link_get_dhcp_route_table(link);
b714d9a6 205 route->mtu = link->network->dhcp_route_mtu;
c0fef8f3
YW
206
207 return dhcp_route_configure(route, link);
e723fbd7
ZJS
208}
209
ff2cf677
YW
210static int link_set_dhcp_route_to_gateway(Link *link, const struct in_addr *gw) {
211 _cleanup_(route_freep) Route *route = NULL;
212 struct in_addr address;
213 int r;
214
215 assert(link);
216 assert(link->dhcp_lease);
217 assert(gw);
218
219 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
220 if (r < 0)
221 return r;
222
223 r = route_new(&route);
224 if (r < 0)
225 return r;
226
227 route->family = AF_INET;
228 route->dst.in = *gw;
229 route->dst_prefixlen = 32;
230 route->prefsrc.in = address;
231 route->scope = RT_SCOPE_LINK;
232 route->protocol = RTPROT_DHCP;
233 route->priority = link->network->dhcp_route_metric;
234 route->table = link_get_dhcp_route_table(link);
235 route->mtu = link->network->dhcp_route_mtu;
236
237 return dhcp_route_configure(route, link);
238}
239
7f206276
YW
240static int dhcp_route_configure_auto(
241 Route *route,
242 Link *link,
243 const struct in_addr *gw) {
244
245 struct in_addr address, netmask, prefix;
246 uint8_t prefixlen;
247 int r;
248
249 assert(route);
250 assert(link);
251 assert(link->dhcp_lease);
252 assert(gw);
253
254 /* The route object may be reused in an iteration. All elements must be set or cleared. */
255
256 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
257 if (r < 0)
258 return r;
259
260 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
261 if (r < 0)
262 return r;
263
264 prefix.s_addr = address.s_addr & netmask.s_addr;
265 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
266
267 if (in4_addr_is_localhost(&route->dst.in)) {
268 if (in4_addr_is_set(gw))
269 log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is localhost, "
270 "ignoring gateway address "IPV4_ADDRESS_FMT_STR,
271 IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
272
273 route->scope = RT_SCOPE_HOST;
274 route->gw_family = AF_UNSPEC;
275 route->gw = IN_ADDR_NULL;
276 route->prefsrc = IN_ADDR_NULL;
277
278 } else if (in4_addr_equal(&route->dst.in, &address)) {
279 if (in4_addr_is_set(gw))
280 log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is equivalent to the acquired address, "
281 "ignoring gateway address "IPV4_ADDRESS_FMT_STR,
282 IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen, IPV4_ADDRESS_FMT_VAL(*gw));
283
284 route->scope = RT_SCOPE_HOST;
285 route->gw_family = AF_UNSPEC;
286 route->gw = IN_ADDR_NULL;
287 route->prefsrc.in = address;
288
289 } else if (route->dst_prefixlen >= prefixlen &&
290 (route->dst.in.s_addr & netmask.s_addr) == prefix.s_addr) {
291 if (in4_addr_is_set(gw))
292 log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is in the assigned network "
293 IPV4_ADDRESS_FMT_STR"/%u, ignoring gateway address "IPV4_ADDRESS_FMT_STR,
294 IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
295 IPV4_ADDRESS_FMT_VAL(prefix), prefixlen,
296 IPV4_ADDRESS_FMT_VAL(*gw));
297
298 route->scope = RT_SCOPE_LINK;
299 route->gw_family = AF_UNSPEC;
300 route->gw = IN_ADDR_NULL;
301 route->prefsrc.in = address;
302
303 } else {
304 if (in4_addr_is_null(gw)) {
305 log_link_debug(link, "DHCP: requested route destination "IPV4_ADDRESS_FMT_STR"/%u is not in the assigned network "
306 IPV4_ADDRESS_FMT_STR"/%u, but no gateway is specified, ignoring.",
307 IPV4_ADDRESS_FMT_VAL(route->dst.in), route->dst_prefixlen,
308 IPV4_ADDRESS_FMT_VAL(prefix), prefixlen);
309 return 0;
310 }
311
312 r = link_set_dhcp_route_to_gateway(link, gw);
313 if (r < 0)
314 return r;
315
316 route->scope = RT_SCOPE_UNIVERSE;
317 route->gw_family = AF_INET;
318 route->gw.in = *gw;
319 route->prefsrc.in = address;
320 }
321
322 return dhcp_route_configure(route, link);
323}
324
afe23f87 325static int link_set_dhcp_static_routes(Link *link, struct in_addr *ret_default_gw) {
f8693fc7 326 _cleanup_free_ sd_dhcp_route **static_routes = NULL;
8cdc46e7 327 bool classless_route = false, static_route = false;
7872d0f7 328 _cleanup_(route_freep) Route *route = NULL;
afe23f87 329 struct in_addr default_gw = {};
cda7fc8d 330 int n, r;
854a1ccf
YW
331
332 assert(link);
333 assert(link->dhcp_lease);
afe23f87 334 assert(ret_default_gw);
854a1ccf 335
7872d0f7 336 if (!link->network->dhcp_use_routes)
854a1ccf
YW
337 return 0;
338
7872d0f7
YW
339 n = sd_dhcp_lease_get_routes(link->dhcp_lease, &static_routes);
340 if (IN_SET(n, 0, -ENODATA)) {
341 log_link_debug(link, "DHCP: No static routes received from DHCP server.");
854a1ccf 342 return 0;
7872d0f7 343 }
854a1ccf 344 if (n < 0)
7872d0f7 345 return n;
854a1ccf 346
7872d0f7
YW
347 for (int i = 0; i < n; i++) {
348 switch (sd_dhcp_route_get_option(static_routes[i])) {
349 case SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE:
350 classless_route = true;
351 break;
352 case SD_DHCP_OPTION_STATIC_ROUTE:
353 static_route = true;
354 break;
355 }
356 }
854a1ccf 357
7872d0f7
YW
358 /* if the DHCP server returns both a Classless Static Routes option and a Static Routes option,
359 * the DHCP client MUST ignore the Static Routes option. */
360 if (classless_route && static_route)
361 log_link_warning(link, "Classless static routes received from DHCP server: ignoring static-route option");
362
363 r = route_new(&route);
364 if (r < 0)
365 return r;
366
367 route->family = AF_INET;
368 route->gw_family = AF_INET;
369 route->protocol = RTPROT_DHCP;
370 route->priority = link->network->dhcp_route_metric;
371 route->table = link_get_dhcp_route_table(link);
372 route->mtu = link->network->dhcp_route_mtu;
373
374 for (int i = 0; i < n; i++) {
7f206276
YW
375 struct in_addr gw;
376
7872d0f7
YW
377 if (sd_dhcp_route_get_option(static_routes[i]) !=
378 (classless_route ? SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE : SD_DHCP_OPTION_STATIC_ROUTE))
379 continue;
854a1ccf 380
7f206276 381 r = sd_dhcp_route_get_gateway(static_routes[i], &gw);
854a1ccf 382 if (r < 0)
7872d0f7 383 return r;
854a1ccf 384
7872d0f7
YW
385 r = sd_dhcp_route_get_destination(static_routes[i], &route->dst.in);
386 if (r < 0)
387 return r;
854a1ccf 388
7872d0f7
YW
389 r = sd_dhcp_route_get_destination_prefix_length(static_routes[i], &route->dst_prefixlen);
390 if (r < 0)
391 return r;
392
afe23f87
YW
393 /* When classless static routes are provided, then router option will be ignored. To
394 * use the default gateway later in other routes, e.g., routes to dns servers, here we
395 * need to find the default gateway in the classless static routes. */
396 if (classless_route &&
397 in4_addr_is_null(&route->dst.in) && route->dst_prefixlen == 0 &&
398 in4_addr_is_null(&default_gw))
399 default_gw = gw;
400
7f206276 401 r = dhcp_route_configure_auto(route, link, &gw);
854a1ccf 402 if (r < 0)
7872d0f7
YW
403 return r;
404 }
405
afe23f87 406 *ret_default_gw = default_gw;
7872d0f7
YW
407 return classless_route;
408}
409
afe23f87 410static int link_set_dhcp_gateway(Link *link, struct in_addr *ret_gw) {
ff2cf677
YW
411 _cleanup_(route_freep) Route *route = NULL;
412 const struct in_addr *router;
413 struct in_addr address;
414 Route *rt;
415 int r;
416
417 assert(link);
418 assert(link->dhcp_lease);
afe23f87 419 assert(ret_gw);
ff2cf677
YW
420
421 if (!link->network->dhcp_use_gateway)
422 return 0;
423
424 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
425 if (r < 0)
426 return r;
427
428 r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
429 if (IN_SET(r, 0, -ENODATA)) {
430 log_link_debug(link, "DHCP: No gateway received from DHCP server.");
431 return 0;
432 }
433 if (r < 0)
434 return r;
435 if (in4_addr_is_null(&router[0])) {
436 log_link_debug(link, "DHCP: Received gateway address is null.");
437 return 0;
438 }
439
440 /* The dhcp netmask may mask out the gateway. First, add an explicit route for the gateway host
441 * so that we can route no matter the netmask or existing kernel route tables. */
442 r = link_set_dhcp_route_to_gateway(link, &router[0]);
443 if (r < 0)
444 return r;
445
446 r = route_new(&route);
447 if (r < 0)
448 return r;
449
450 /* Next, add a default gateway. */
451 route->family = AF_INET;
452 route->gw_family = AF_INET;
453 route->gw.in = router[0];
454 route->prefsrc.in = address;
455 route->protocol = RTPROT_DHCP;
456 route->priority = link->network->dhcp_route_metric;
457 route->table = link_get_dhcp_route_table(link);
458 route->mtu = link->network->dhcp_route_mtu;
459
460 r = dhcp_route_configure(route, link);
461 if (r < 0)
462 return r;
463
464 HASHMAP_FOREACH(rt, link->network->routes_by_section) {
465 if (!rt->gateway_from_dhcp_or_ra)
466 continue;
467
468 if (rt->gw_family != AF_INET)
469 continue;
470
471 rt->gw.in = router[0];
472 if (!rt->protocol_set)
473 rt->protocol = RTPROT_DHCP;
474 if (!rt->priority_set)
475 rt->priority = link->network->dhcp_route_metric;
476 if (!rt->table_set)
477 rt->table = link_get_dhcp_route_table(link);
478 if (rt->mtu == 0)
479 rt->mtu = link->network->dhcp_route_mtu;
480
481 r = dhcp_route_configure(rt, link);
482 if (r < 0)
483 return r;
854a1ccf
YW
484 }
485
afe23f87 486 *ret_gw = router[0];
854a1ccf
YW
487 return 0;
488}
489
afe23f87 490static int link_set_dns_routes(Link *link, const struct in_addr *gw) {
e1c08a3d
YW
491 _cleanup_(route_freep) Route *route = NULL;
492 const struct in_addr *dns;
e1c08a3d
YW
493 int n, r;
494
495 assert(link);
496 assert(link->dhcp_lease);
497 assert(link->network);
afe23f87 498 assert(gw);
e723fbd7 499
e1c08a3d
YW
500 if (!link->network->dhcp_use_dns ||
501 !link->network->dhcp_routes_to_dns)
502 return 0;
e723fbd7 503
e1c08a3d
YW
504 n = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
505 if (IN_SET(n, 0, -ENODATA))
506 return 0;
507 if (n < 0)
508 return n;
509
e723fbd7
ZJS
510 r = route_new(&route);
511 if (r < 0)
512 return r;
513
514 route->family = AF_INET;
e1c08a3d 515 route->dst_prefixlen = 32;
e723fbd7 516 route->protocol = RTPROT_DHCP;
e1c08a3d
YW
517 route->priority = link->network->dhcp_route_metric;
518 route->table = link_get_dhcp_route_table(link);
b714d9a6 519 route->mtu = link->network->dhcp_route_mtu;
e1c08a3d
YW
520
521 for (int i = 0; i < n; i ++) {
522 route->dst.in = dns[i];
523
afe23f87 524 r = dhcp_route_configure_auto(route, link, gw);
e1c08a3d
YW
525 if (r < 0)
526 return r;
527 }
528
e723fbd7
ZJS
529 return 0;
530}
531
3c9b8860 532static int link_set_dhcp_routes(Link *link) {
afe23f87 533 struct in_addr gw = {};
6e537f62 534 Route *rt;
7872d0f7 535 int r;
3c9b8860
TG
536
537 assert(link);
0c9b15a3
AJ
538
539 if (!link->dhcp_lease) /* link went down while we configured the IP addresses? */
540 return 0;
541
542 if (!link->network) /* link went down while we configured the IP addresses? */
543 return 0;
964b26fe 544
4e2ef9d9
YW
545 if (!link_has_carrier(link) && !link->network->configure_without_carrier)
546 /* During configuring addresses, the link lost its carrier. As networkd is dropping
547 * the addresses now, let's not configure the routes either. */
548 return 0;
549
6e537f62
YW
550 while ((rt = set_steal_first(link->dhcp_routes))) {
551 r = set_ensure_put(&link->dhcp_routes_old, &route_hash_ops, rt);
552 if (r < 0)
553 return log_link_error_errno(link, r, "Failed to store old DHCPv4 route: %m");
554 }
d4c52ee5 555
c0fef8f3 556 r = link_set_dhcp_prefix_route(link);
b23aec0d 557 if (r < 0)
c0fef8f3 558 return log_link_error_errno(link, r, "DHCP error: Could not set prefix route: %m");
156ddf8d 559
afe23f87 560 r = link_set_dhcp_static_routes(link, &gw);
7872d0f7
YW
561 if (r < 0)
562 return log_link_error_errno(link, r, "DHCP error: Could not set static routes: %m");
ff2cf677 563 if (r == 0) {
7872d0f7
YW
564 /* According to RFC 3442: If the DHCP server returns both a Classless Static Routes option and
565 * a Router option, the DHCP client MUST ignore the Router option. */
afe23f87 566 r = link_set_dhcp_gateway(link, &gw);
156ddf8d 567 if (r < 0)
ff2cf677 568 return log_link_error_errno(link, r, "DHCP error: Could not set gateway: %m");
5f04a209
SS
569 }
570
afe23f87 571 r = link_set_dns_routes(link, &gw);
e1c08a3d
YW
572 if (r < 0)
573 return log_link_error_errno(link, r, "DHCP error: Could not set routes to DNS servers: %m");
1985c54f 574
e1c08a3d 575 return 0;
3c9b8860
TG
576}
577
7fa472f9
YW
578static int dhcp_reset_mtu(Link *link) {
579 uint16_t mtu;
580 int r;
581
582 assert(link);
583
584 if (!link->network->dhcp_use_mtu)
585 return 0;
586
587 r = sd_dhcp_lease_get_mtu(link->dhcp_lease, &mtu);
46b875fb
YW
588 if (r == -ENODATA)
589 return 0;
7fa472f9 590 if (r < 0)
46b875fb 591 return log_link_error_errno(link, r, "DHCP error: failed to get MTU from lease: %m");
7fa472f9
YW
592
593 if (link->original_mtu == mtu)
594 return 0;
595
596 r = link_set_mtu(link, link->original_mtu);
46b875fb
YW
597 if (r < 0)
598 return log_link_error_errno(link, r, "DHCP error: could not reset MTU: %m");
3c9b8860 599
7fa472f9
YW
600 return 0;
601}
602
603static int dhcp_reset_hostname(Link *link) {
604 const char *hostname;
605 int r;
606
607 assert(link);
608
609 if (!link->network->dhcp_use_hostname)
610 return 0;
611
612 hostname = link->network->dhcp_hostname;
613 if (!hostname)
614 (void) sd_dhcp_lease_get_hostname(link->dhcp_lease, &hostname);
615
616 if (!hostname)
617 return 0;
618
619 /* If a hostname was set due to the lease, then unset it now. */
620 r = manager_set_hostname(link->manager, NULL);
621 if (r < 0)
622 return log_link_error_errno(link, r, "DHCP error: Failed to reset transient hostname: %m");
623
624 return 0;
625}
626
6906794d
YW
627static int dhcp4_remove_route_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
628 int r;
629
630 assert(m);
631 assert(link);
632 assert(link->dhcp4_remove_messages > 0);
633
634 link->dhcp4_remove_messages--;
635
636 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
637 return 1;
638
639 r = sd_netlink_message_get_errno(m);
640 if (r < 0 && r != -ESRCH)
641 log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 route, ignoring");
642
643 if (link->dhcp4_remove_messages == 0) {
644 r = dhcp4_update_address(link, false);
645 if (r < 0)
646 link_enter_failed(link);
647 }
648
649 return 1;
650}
651
652static int dhcp4_remove_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
653 int r;
654
655 assert(m);
656 assert(link);
657 assert(link->dhcp4_remove_messages > 0);
658
659 link->dhcp4_remove_messages--;
660
661 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
662 return 1;
663
664 r = sd_netlink_message_get_errno(m);
665 if (r < 0 && r != -EADDRNOTAVAIL)
666 log_link_message_warning_errno(link, m, r, "Failed to remove DHCPv4 address, ignoring");
667 else
668 (void) manager_rtnl_process_address(rtnl, m, link->manager);
669
670 if (link->dhcp4_remove_messages == 0) {
671 r = dhcp4_update_address(link, false);
672 if (r < 0)
673 link_enter_failed(link);
674 }
675
676 return 1;
677}
678
679static int dhcp4_remove_all(Link *link) {
6e537f62 680 Route *route;
6e537f62 681 int k, r = 0;
6906794d
YW
682
683 assert(link);
6906794d 684
90e74a66 685 SET_FOREACH(route, link->dhcp_routes) {
ad208fac 686 k = route_remove(route, NULL, link, dhcp4_remove_route_handler);
6e537f62
YW
687 if (k < 0)
688 r = k;
689 else
690 link->dhcp4_remove_messages++;
691 }
6906794d 692
6e537f62
YW
693 if (link->dhcp_address) {
694 k = address_remove(link->dhcp_address, link, dhcp4_remove_address_handler);
695 if (k < 0)
696 r = k;
697 else
698 link->dhcp4_remove_messages++;
699 }
6906794d 700
6e537f62 701 return r;
6906794d
YW
702}
703
7fa472f9 704static int dhcp_lease_lost(Link *link) {
2ac7eec3 705 int k, r = 0;
7fa472f9
YW
706
707 assert(link);
708 assert(link->dhcp_lease);
709
f8c2e4b9 710 log_link_info(link, "DHCP lease lost");
7fa472f9
YW
711
712 link->dhcp4_configured = false;
713
75be72d1 714 /* dhcp_lease_lost() may be called during renewing IP address. */
c45fdad6 715 k = dhcp4_release_old_lease(link);
6e537f62
YW
716 if (k < 0)
717 r = k;
75be72d1 718
6e537f62
YW
719 k = dhcp4_remove_all(link);
720 if (k < 0)
721 r = k;
6906794d 722
6e537f62
YW
723 k = dhcp_reset_mtu(link);
724 if (k < 0)
725 r = k;
6906794d 726
6e537f62
YW
727 k = dhcp_reset_hostname(link);
728 if (k < 0)
729 r = k;
7fa472f9 730
3c9b8860 731 link->dhcp_lease = sd_dhcp_lease_unref(link->dhcp_lease);
6a3e5f6a 732 link_dirty(link);
3c9b8860 733
84add3cd 734 (void) sd_ipv4acd_stop(link->dhcp_acd);
66f507e1 735
6e537f62 736 return r;
3c9b8860
TG
737}
738
0f3ff4ea
SS
739static void dhcp_address_on_acd(sd_ipv4acd *acd, int event, void *userdata) {
740 _cleanup_free_ char *pretty = NULL;
741 union in_addr_union address = {};
742 Link *link;
743 int r;
744
745 assert(acd);
746 assert(userdata);
747
748 link = userdata;
749
750 switch (event) {
751 case SD_IPV4ACD_EVENT_STOP:
752 log_link_debug(link, "Stopping ACD client for DHCP4...");
753 return;
754
755 case SD_IPV4ACD_EVENT_BIND:
756 if (DEBUG_LOGGING) {
757 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
758 (void) in_addr_to_string(AF_INET, &address, &pretty);
759 log_link_debug(link, "Successfully claimed DHCP4 address %s", strna(pretty));
760 }
153cf041 761 link->dhcp4_address_bind = true;
c1d3fa29 762 dhcp4_check_ready(link);
0f3ff4ea
SS
763 break;
764
765 case SD_IPV4ACD_EVENT_CONFLICT:
766 (void) sd_dhcp_lease_get_address(link->dhcp_lease, &address.in);
767 (void) in_addr_to_string(AF_INET, &address, &pretty);
768 log_link_warning(link, "DAD conflict. Dropping DHCP4 address %s", strna(pretty));
769
f766d9af
YW
770 r = sd_dhcp_client_send_decline(link->dhcp_client);
771 if (r < 0)
772 log_link_warning_errno(link, r, "Failed to send DHCP DECLINE, ignoring: %m");
0f3ff4ea
SS
773
774 if (link->dhcp_lease) {
775 r = dhcp_lease_lost(link);
776 if (r < 0)
777 link_enter_failed(link);
778 }
779 break;
780
781 default:
782 assert_not_reached("Invalid IPv4ACD event.");
783 }
784
dce1cd41 785 (void) sd_ipv4acd_stop(acd);
0f3ff4ea
SS
786
787 return;
788}
789
10fa21c0 790static int dhcp4_configure_dad(Link *link) {
0f3ff4ea
SS
791 int r;
792
793 assert(link);
10fa21c0
YW
794 assert(link->manager);
795 assert(link->network);
0f3ff4ea 796
10fa21c0
YW
797 if (!link->network->dhcp_send_decline)
798 return 0;
0f3ff4ea 799
10fa21c0
YW
800 if (!link->dhcp_acd) {
801 r = sd_ipv4acd_new(&link->dhcp_acd);
802 if (r < 0)
803 return r;
0f3ff4ea 804
10fa21c0
YW
805 r = sd_ipv4acd_attach_event(link->dhcp_acd, link->manager->event, 0);
806 if (r < 0)
807 return r;
808 }
0f3ff4ea 809
10fa21c0 810 r = sd_ipv4acd_set_ifindex(link->dhcp_acd, link->ifindex);
0f3ff4ea
SS
811 if (r < 0)
812 return r;
813
b8162cd2 814 r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether);
0f3ff4ea
SS
815 if (r < 0)
816 return r;
817
0f3ff4ea
SS
818 return 0;
819}
820
54312274
YW
821static int dhcp4_dad_update_mac(Link *link) {
822 bool running;
823 int r;
824
825 assert(link);
826
827 if (!link->dhcp_acd)
828 return 0;
829
830 running = sd_ipv4acd_is_running(link->dhcp_acd);
831
832 r = sd_ipv4acd_stop(link->dhcp_acd);
0f3ff4ea
SS
833 if (r < 0)
834 return r;
835
b8162cd2 836 r = sd_ipv4acd_set_mac(link->dhcp_acd, &link->hw_addr.addr.ether);
0f3ff4ea
SS
837 if (r < 0)
838 return r;
839
54312274
YW
840 if (running) {
841 r = sd_ipv4acd_start(link->dhcp_acd, true);
842 if (r < 0)
843 return r;
844 }
845
0f3ff4ea
SS
846 return 0;
847}
848
153cf041
YW
849static int dhcp4_start_acd(Link *link) {
850 union in_addr_union addr;
687b3bc6 851 struct in_addr old;
153cf041
YW
852 int r;
853
854 if (!link->network->dhcp_send_decline)
855 return 0;
856
857 if (!link->dhcp_lease)
858 return 0;
859
10fa21c0 860 (void) sd_ipv4acd_stop(link->dhcp_acd);
5acf54a0 861
153cf041
YW
862 link->dhcp4_address_bind = false;
863
864 r = sd_dhcp_lease_get_address(link->dhcp_lease, &addr.in);
865 if (r < 0)
866 return r;
867
10fa21c0 868 r = sd_ipv4acd_get_address(link->dhcp_acd, &old);
687b3bc6
YW
869 if (r < 0)
870 return r;
871
10fa21c0 872 r = sd_ipv4acd_set_address(link->dhcp_acd, &addr.in);
153cf041
YW
873 if (r < 0)
874 return r;
875
10fa21c0 876 r = sd_ipv4acd_set_callback(link->dhcp_acd, dhcp_address_on_acd, link);
153cf041
YW
877 if (r < 0)
878 return r;
879
880 if (DEBUG_LOGGING) {
881 _cleanup_free_ char *pretty = NULL;
882
883 (void) in_addr_to_string(AF_INET, &addr, &pretty);
884 log_link_debug(link, "Starting IPv4ACD client. Probing DHCPv4 address %s", strna(pretty));
885 }
886
10fa21c0 887 r = sd_ipv4acd_start(link->dhcp_acd, !in4_addr_equal(&addr.in, &old));
153cf041
YW
888 if (r < 0)
889 return r;
890
891 return 1;
892}
893
c45fdad6
YW
894static int dhcp4_address_ready_callback(Address *address) {
895 Link *link;
896 int r;
897
898 assert(address);
899
900 link = address->link;
901
902 /* Do not call this again. */
903 address->callback = NULL;
904
905 r = link_set_dhcp_routes(link);
906 if (r < 0)
907 return r;
908
909 /* Reconfigure static routes as kernel may remove some routes when lease expires. */
141318f7 910 r = link_set_routes(link);
c45fdad6
YW
911 if (r < 0)
912 return r;
913
914 r = dhcp4_start_acd(link);
915 if (r < 0)
69e3234d 916 return log_link_error_errno(link, r, "Failed to start IPv4ACD for DHCP4 address: %m");
c45fdad6
YW
917
918 dhcp4_check_ready(link);
919 return 0;
920}
921
302a796f 922static int dhcp4_address_handler(sd_netlink *rtnl, sd_netlink_message *m, Link *link) {
3c9b8860
TG
923 int r;
924
925 assert(link);
926
3ab7ed3f
YW
927 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
928 return 1;
929
1c4baffc 930 r = sd_netlink_message_get_errno(m);
3c9b8860 931 if (r < 0 && r != -EEXIST) {
5ecb131d 932 log_link_message_warning_errno(link, m, r, "Could not set DHCPv4 address");
3c9b8860 933 link_enter_failed(link);
3ab7ed3f 934 return 1;
4ff296b0
YW
935 } else if (r >= 0)
936 (void) manager_rtnl_process_address(rtnl, m, link->manager);
3c9b8860 937
c45fdad6
YW
938 if (address_is_ready(link->dhcp_address)) {
939 r = dhcp4_address_ready_callback(link->dhcp_address);
940 if (r < 0) {
941 link_enter_failed(link);
942 return 1;
943 }
944 } else
945 link->dhcp_address->callback = dhcp4_address_ready_callback;
0f3ff4ea 946
3c9b8860
TG
947 return 1;
948}
949
6906794d 950static int dhcp4_update_address(Link *link, bool announce) {
8e766630 951 _cleanup_(address_freep) Address *addr = NULL;
6906794d
YW
952 uint32_t lifetime = CACHE_INFO_INFINITY_LIFE_TIME;
953 struct in_addr address, netmask;
3c9b8860 954 unsigned prefixlen;
6e537f62 955 Address *ret;
3c9b8860
TG
956 int r;
957
6906794d
YW
958 assert(link);
959 assert(link->network);
960
961 if (!link->dhcp_lease)
962 return 0;
963
964 link_set_state(link, LINK_STATE_CONFIGURING);
965 link->dhcp4_configured = false;
3c9b8860 966
141318f7
YW
967 /* address_handler calls link_set_routes() and link_set_nexthop(). Before they are called, the
968 * related flags must be cleared. Otherwise, the link becomes configured state before routes
969 * are configured. */
0c816fcc
YW
970 link->static_routes_configured = false;
971 link->static_nexthops_configured = false;
972
6906794d
YW
973 r = sd_dhcp_lease_get_address(link->dhcp_lease, &address);
974 if (r < 0)
975 return log_link_warning_errno(link, r, "DHCP error: no address: %m");
976
977 r = sd_dhcp_lease_get_netmask(link->dhcp_lease, &netmask);
978 if (r < 0)
979 return log_link_warning_errno(link, r, "DHCP error: no netmask: %m");
980
981 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
982 r = sd_dhcp_lease_get_lifetime(link->dhcp_lease, &lifetime);
983 if (r < 0)
984 return log_link_warning_errno(link, r, "DHCP error: no lifetime: %m");
985 }
986
987 prefixlen = in4_addr_netmask_to_prefixlen(&netmask);
988
989 if (announce) {
990 const struct in_addr *router;
991
992 r = sd_dhcp_lease_get_router(link->dhcp_lease, &router);
993 if (r < 0 && r != -ENODATA)
994 return log_link_error_errno(link, r, "DHCP error: Could not get gateway: %m");
995
94876904 996 if (r > 0 && in4_addr_is_set(&router[0]))
6906794d
YW
997 log_struct(LOG_INFO,
998 LOG_LINK_INTERFACE(link),
ceea6c1a
YW
999 LOG_LINK_MESSAGE(link, "DHCPv4 address "IPV4_ADDRESS_FMT_STR"/%u via "IPV4_ADDRESS_FMT_STR,
1000 IPV4_ADDRESS_FMT_VAL(address),
6906794d 1001 prefixlen,
ceea6c1a
YW
1002 IPV4_ADDRESS_FMT_VAL(router[0])),
1003 "ADDRESS="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address),
6906794d 1004 "PREFIXLEN=%u", prefixlen,
ceea6c1a 1005 "GATEWAY="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(router[0]));
6906794d
YW
1006 else
1007 log_struct(LOG_INFO,
1008 LOG_LINK_INTERFACE(link),
ceea6c1a
YW
1009 LOG_LINK_MESSAGE(link, "DHCPv4 address "IPV4_ADDRESS_FMT_STR"/%u",
1010 IPV4_ADDRESS_FMT_VAL(address),
6906794d 1011 prefixlen),
ceea6c1a 1012 "ADDRESS="IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(address),
6906794d
YW
1013 "PREFIXLEN=%u", prefixlen);
1014 }
3c9b8860 1015
f0213e37 1016 r = address_new(&addr);
3c9b8860 1017 if (r < 0)
6906794d 1018 return log_oom();
3c9b8860
TG
1019
1020 addr->family = AF_INET;
6906794d 1021 addr->in_addr.in.s_addr = address.s_addr;
3c9b8860
TG
1022 addr->cinfo.ifa_prefered = lifetime;
1023 addr->cinfo.ifa_valid = lifetime;
1024 addr->prefixlen = prefixlen;
df8aa086
YW
1025 if (prefixlen <= 30)
1026 addr->broadcast.s_addr = address.s_addr | ~netmask.s_addr;
eaff204f 1027 SET_FLAG(addr->flags, IFA_F_NOPREFIXROUTE, !link_prefixroute(link));
415deef9 1028 addr->route_metric = link->network->dhcp_route_metric;
3c9b8860 1029
66669078
TG
1030 /* allow reusing an existing address and simply update its lifetime
1031 * in case it already exists */
37c0b601 1032 r = address_configure(addr, link, dhcp4_address_handler, &ret);
3c9b8860 1033 if (r < 0)
6e537f62
YW
1034 return log_link_error_errno(link, r, "Failed to set DHCPv4 address: %m");
1035
1036 if (!address_equal(link->dhcp_address, ret))
1037 link->dhcp_address_old = link->dhcp_address;
1038 link->dhcp_address = ret;
3c9b8860
TG
1039
1040 return 0;
1041}
1042
1043static int dhcp_lease_renew(sd_dhcp_client *client, Link *link) {
1044 sd_dhcp_lease *lease;
3c9b8860
TG
1045 int r;
1046
1047 assert(link);
1048 assert(client);
3c9b8860
TG
1049
1050 r = sd_dhcp_client_get_lease(client, &lease);
f6b8196f
LP
1051 if (r < 0)
1052 return log_link_warning_errno(link, r, "DHCP error: no lease: %m");
3c9b8860
TG
1053
1054 sd_dhcp_lease_unref(link->dhcp_lease);
e6b18ffa 1055 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 1056 link_dirty(link);
3c9b8860 1057
6906794d 1058 return dhcp4_update_address(link, false);
3c9b8860
TG
1059}
1060
1061static int dhcp_lease_acquired(sd_dhcp_client *client, Link *link) {
1062 sd_dhcp_lease *lease;
3c9b8860
TG
1063 int r;
1064
1065 assert(client);
1066 assert(link);
1067
1068 r = sd_dhcp_client_get_lease(client, &lease);
f2341e0a 1069 if (r < 0)
f6b8196f 1070 return log_link_error_errno(link, r, "DHCP error: No lease: %m");
3c9b8860 1071
6906794d 1072 sd_dhcp_lease_unref(link->dhcp_lease);
e6b18ffa 1073 link->dhcp_lease = sd_dhcp_lease_ref(lease);
6a3e5f6a 1074 link_dirty(link);
3c9b8860 1075
27cb34f5 1076 if (link->network->dhcp_use_mtu) {
3c9b8860
TG
1077 uint16_t mtu;
1078
1079 r = sd_dhcp_lease_get_mtu(lease, &mtu);
1080 if (r >= 0) {
933c70a0 1081 r = link_set_mtu(link, mtu);
3c9b8860 1082 if (r < 0)
f2341e0a 1083 log_link_error_errno(link, r, "Failed to set MTU to %" PRIu16 ": %m", mtu);
3c9b8860
TG
1084 }
1085 }
1086
27cb34f5 1087 if (link->network->dhcp_use_hostname) {
2de2abad
LB
1088 const char *dhcpname = NULL;
1089 _cleanup_free_ char *hostname = NULL;
3c9b8860 1090
27cb34f5 1091 if (link->network->dhcp_hostname)
2de2abad 1092 dhcpname = link->network->dhcp_hostname;
dce391e7 1093 else
2de2abad
LB
1094 (void) sd_dhcp_lease_get_hostname(lease, &dhcpname);
1095
1096 if (dhcpname) {
1097 r = shorten_overlong(dhcpname, &hostname);
1098 if (r < 0)
1099 log_link_warning_errno(link, r, "Unable to shorten overlong DHCP hostname '%s', ignoring: %m", dhcpname);
1100 if (r == 1)
5238e957 1101 log_link_notice(link, "Overlong DHCP hostname received, shortened from '%s' to '%s'", dhcpname, hostname);
2de2abad 1102 }
a7d0ef44 1103
dce391e7 1104 if (hostname) {
59eb33e0 1105 r = manager_set_hostname(link->manager, hostname);
3c9b8860 1106 if (r < 0)
f2341e0a 1107 log_link_error_errno(link, r, "Failed to set transient hostname to '%s': %m", hostname);
3c9b8860
TG
1108 }
1109 }
1110
27cb34f5 1111 if (link->network->dhcp_use_timezone) {
21b80ad1
LP
1112 const char *tz = NULL;
1113
1114 (void) sd_dhcp_lease_get_timezone(link->dhcp_lease, &tz);
1115
1116 if (tz) {
59eb33e0 1117 r = manager_set_timezone(link->manager, tz);
21b80ad1
LP
1118 if (r < 0)
1119 log_link_error_errno(link, r, "Failed to set timezone to '%s': %m", tz);
1120 }
1121 }
1122
6906794d
YW
1123 if (link->dhcp4_remove_messages == 0) {
1124 r = dhcp4_update_address(link, true);
1125 if (r < 0)
1126 return r;
1127 } else
1128 log_link_debug(link,
1129 "The link has previously assigned DHCPv4 address or routes. "
1130 "The newly assigned address and routes will set up after old ones are removed.");
3c9b8860
TG
1131
1132 return 0;
1133}
8bc17bb3 1134
d03073dd
YW
1135static int dhcp_lease_ip_change(sd_dhcp_client *client, Link *link) {
1136 int r;
1137
d03073dd 1138 r = dhcp_lease_acquired(client, link);
6e537f62 1139 if (r < 0)
d03073dd 1140 (void) dhcp_lease_lost(link);
d03073dd 1141
6e537f62 1142 return r;
d03073dd
YW
1143}
1144
6b000af4 1145static int dhcp_server_is_deny_listed(Link *link, sd_dhcp_client *client) {
727b5734
SS
1146 sd_dhcp_lease *lease;
1147 struct in_addr addr;
1148 int r;
1149
1150 assert(link);
1151 assert(link->network);
1152 assert(client);
1153
1154 r = sd_dhcp_client_get_lease(client, &lease);
1155 if (r < 0)
1156 return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
1157
1158 r = sd_dhcp_lease_get_server_identifier(lease, &addr);
1159 if (r < 0)
0da425df 1160 return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
727b5734 1161
6b000af4 1162 if (set_contains(link->network->dhcp_deny_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
727b5734
SS
1163 log_struct(LOG_DEBUG,
1164 LOG_LINK_INTERFACE(link),
ceea6c1a
YW
1165 LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in deny-list, ignoring offer",
1166 IPV4_ADDRESS_FMT_VAL(addr)));
727b5734
SS
1167 return true;
1168 }
1169
1170 return false;
1171}
1172
98ebef62
SS
1173static int dhcp_server_is_allow_listed(Link *link, sd_dhcp_client *client) {
1174 sd_dhcp_lease *lease;
1175 struct in_addr addr;
1176 int r;
1177
1178 assert(link);
1179 assert(link->network);
1180 assert(client);
1181
1182 r = sd_dhcp_client_get_lease(client, &lease);
1183 if (r < 0)
1184 return log_link_error_errno(link, r, "Failed to get DHCP lease: %m");
1185
1186 r = sd_dhcp_lease_get_server_identifier(lease, &addr);
1187 if (r < 0)
0da425df 1188 return log_link_debug_errno(link, r, "Failed to get DHCP server IP address: %m");
98ebef62
SS
1189
1190 if (set_contains(link->network->dhcp_allow_listed_ip, UINT32_TO_PTR(addr.s_addr))) {
1191 log_struct(LOG_DEBUG,
1192 LOG_LINK_INTERFACE(link),
ceea6c1a
YW
1193 LOG_LINK_MESSAGE(link, "DHCPv4 server IP address "IPV4_ADDRESS_FMT_STR" found in allow-list, accepting offer",
1194 IPV4_ADDRESS_FMT_VAL(addr)));
98ebef62
SS
1195 return true;
1196 }
1197
1198 return false;
1199}
1200
727b5734 1201static int dhcp4_handler(sd_dhcp_client *client, int event, void *userdata) {
3c9b8860 1202 Link *link = userdata;
86e2be7b 1203 int r;
3c9b8860
TG
1204
1205 assert(link);
1206 assert(link->network);
1207 assert(link->manager);
1208
1209 if (IN_SET(link->state, LINK_STATE_FAILED, LINK_STATE_LINGER))
727b5734 1210 return 0;
3c9b8860
TG
1211
1212 switch (event) {
03748142 1213 case SD_DHCP_CLIENT_EVENT_STOP:
0b4b66cc 1214 if (link->ipv4ll) {
8bc17bb3
SS
1215 log_link_debug(link, "DHCP client is stopped. Acquiring IPv4 link-local address");
1216
1217 r = sd_ipv4ll_start(link->ipv4ll);
727b5734
SS
1218 if (r < 0)
1219 return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
8bc17bb3
SS
1220 }
1221
7da377ef 1222 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
efdb62df
YW
1223 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
1224 return 0;
1225 }
1226
efdb62df 1227 if (link->dhcp_lease) {
f766d9af
YW
1228 if (link->network->dhcp_send_release) {
1229 r = sd_dhcp_client_send_release(client);
1230 if (r < 0)
1231 log_link_warning_errno(link, r, "Failed to send DHCP RELEASE, ignoring: %m");
1232 }
8bea7e70 1233
efdb62df
YW
1234 r = dhcp_lease_lost(link);
1235 if (r < 0) {
1236 link_enter_failed(link);
1237 return r;
1238 }
1239 }
1240
1241 break;
8bc17bb3 1242 case SD_DHCP_CLIENT_EVENT_EXPIRED:
7da377ef 1243 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
efdb62df 1244 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
727b5734 1245 return 0;
3c9b8860
TG
1246 }
1247
1248 if (link->dhcp_lease) {
1249 r = dhcp_lease_lost(link);
1250 if (r < 0) {
1251 link_enter_failed(link);
727b5734 1252 return r;
3c9b8860
TG
1253 }
1254 }
1255
d03073dd
YW
1256 break;
1257 case SD_DHCP_CLIENT_EVENT_IP_CHANGE:
1258 if (FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP)) {
1259 log_link_notice(link, "DHCPv4 connection considered critical, ignoring request to reconfigure it.");
1260 return 0;
1261 }
1262
1263 r = dhcp_lease_ip_change(client, link);
1264 if (r < 0) {
1265 link_enter_failed(link);
1266 return r;
3c9b8860
TG
1267 }
1268
1269 break;
03748142 1270 case SD_DHCP_CLIENT_EVENT_RENEW:
3c9b8860
TG
1271 r = dhcp_lease_renew(client, link);
1272 if (r < 0) {
1273 link_enter_failed(link);
727b5734 1274 return r;
3c9b8860
TG
1275 }
1276 break;
03748142 1277 case SD_DHCP_CLIENT_EVENT_IP_ACQUIRE:
3c9b8860
TG
1278 r = dhcp_lease_acquired(client, link);
1279 if (r < 0) {
1280 link_enter_failed(link);
727b5734 1281 return r;
3c9b8860
TG
1282 }
1283 break;
727b5734 1284 case SD_DHCP_CLIENT_EVENT_SELECTING:
98ebef62
SS
1285 if (!set_isempty(link->network->dhcp_allow_listed_ip)) {
1286 r = dhcp_server_is_allow_listed(link, client);
1287 if (r < 0)
1288 return r;
1289 if (r == 0)
1290 return -ENOMSG;
1291 } else {
1292 r = dhcp_server_is_deny_listed(link, client);
1293 if (r < 0)
1294 return r;
1295 if (r != 0)
1296 return -ENOMSG;
1297 }
727b5734 1298 break;
0107b769
ZJS
1299
1300 case SD_DHCP_CLIENT_EVENT_TRANSIENT_FAILURE:
0b4b66cc
YW
1301 if (link->ipv4ll && !sd_ipv4ll_is_running(link->ipv4ll)) {
1302 log_link_debug(link, "Problems acquiring DHCP lease, acquiring IPv4 link-local address");
0107b769 1303
0b4b66cc
YW
1304 r = sd_ipv4ll_start(link->ipv4ll);
1305 if (r < 0)
1306 return log_link_warning_errno(link, r, "Could not acquire IPv4 link-local address: %m");
0107b769
ZJS
1307 }
1308 break;
1309
3c9b8860
TG
1310 default:
1311 if (event < 0)
f6b8196f 1312 log_link_warning_errno(link, event, "DHCP error: Client failed: %m");
3c9b8860 1313 else
f6b8196f 1314 log_link_warning(link, "DHCP unknown event: %i", event);
3c9b8860
TG
1315 break;
1316 }
1317
727b5734 1318 return 0;
3c9b8860
TG
1319}
1320
7192bb81
LP
1321static int dhcp4_set_hostname(Link *link) {
1322 _cleanup_free_ char *hostname = NULL;
1323 const char *hn;
1324 int r;
1325
1326 assert(link);
1327
1328 if (!link->network->dhcp_send_hostname)
1329 hn = NULL;
1330 else if (link->network->dhcp_hostname)
1331 hn = link->network->dhcp_hostname;
1332 else {
1333 r = gethostname_strict(&hostname);
1334 if (r < 0 && r != -ENXIO) /* ENXIO: no hostname set or hostname is "localhost" */
62f12d75 1335 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to get hostname: %m");
7192bb81
LP
1336
1337 hn = hostname;
1338 }
1339
a8494759
YW
1340 r = sd_dhcp_client_set_hostname(link->dhcp_client, hn);
1341 if (r == -EINVAL && hostname)
1342 /* Ignore error when the machine's hostname is not suitable to send in DHCP packet. */
62f12d75 1343 log_link_debug_errno(link, r, "DHCP4 CLIENT: Failed to set hostname from kernel hostname, ignoring: %m");
a8494759 1344 else if (r < 0)
62f12d75 1345 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set hostname: %m");
64b21ece
MV
1346
1347 return 0;
1348}
1349
d947f7f9 1350static int dhcp4_set_client_identifier(Link *link) {
fff1f40c
YW
1351 int r;
1352
1353 assert(link);
1354 assert(link->network);
1355 assert(link->dhcp_client);
1356
1357 switch (link->network->dhcp_client_identifier) {
1358 case DHCP_CLIENT_ID_DUID: {
0cf7c3fd 1359 /* If configured, apply user specified DUID and IAID */
4e26a5ba 1360 const DUID *duid = link_get_dhcp4_duid(link);
fff1f40c 1361
0cf7c3fd
YW
1362 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
1363 r = sd_dhcp_client_set_iaid_duid_llt(link->dhcp_client,
4e26a5ba
YW
1364 link->network->dhcp_iaid_set,
1365 link->network->dhcp_iaid,
0cf7c3fd
YW
1366 duid->llt_time);
1367 else
1368 r = sd_dhcp_client_set_iaid_duid(link->dhcp_client,
4e26a5ba
YW
1369 link->network->dhcp_iaid_set,
1370 link->network->dhcp_iaid,
0cf7c3fd
YW
1371 duid->type,
1372 duid->raw_data_len > 0 ? duid->raw_data : NULL,
1373 duid->raw_data_len);
fff1f40c 1374 if (r < 0)
62f12d75 1375 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IAID+DUID: %m");
fff1f40c
YW
1376 break;
1377 }
1378 case DHCP_CLIENT_ID_DUID_ONLY: {
1379 /* If configured, apply user specified DUID */
4e26a5ba 1380 const DUID *duid = link_get_dhcp4_duid(link);
fff1f40c 1381
0cf7c3fd
YW
1382 if (duid->type == DUID_TYPE_LLT && duid->raw_data_len == 0)
1383 r = sd_dhcp_client_set_duid_llt(link->dhcp_client,
89b3fa66 1384 duid->llt_time);
0cf7c3fd
YW
1385 else
1386 r = sd_dhcp_client_set_duid(link->dhcp_client,
1387 duid->type,
1388 duid->raw_data_len > 0 ? duid->raw_data : NULL,
1389 duid->raw_data_len);
fff1f40c 1390 if (r < 0)
62f12d75 1391 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set DUID: %m");
fff1f40c
YW
1392 break;
1393 }
14b66dbc
TR
1394 case DHCP_CLIENT_ID_MAC: {
1395 const uint8_t *hw_addr = link->hw_addr.addr.bytes;
1396 size_t hw_addr_len = link->hw_addr.length;
1397
1398 if (link->iftype == ARPHRD_INFINIBAND && hw_addr_len == INFINIBAND_ALEN) {
1399 /* set_client_id expects only last 8 bytes of an IB address */
1400 hw_addr += INFINIBAND_ALEN - 8;
1401 hw_addr_len -= INFINIBAND_ALEN - 8;
1402 }
1403
fff1f40c 1404 r = sd_dhcp_client_set_client_id(link->dhcp_client,
14b66dbc
TR
1405 link->iftype,
1406 hw_addr,
1407 hw_addr_len);
fff1f40c 1408 if (r < 0)
62f12d75 1409 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set client ID: %m");
fff1f40c 1410 break;
14b66dbc 1411 }
fff1f40c
YW
1412 default:
1413 assert_not_reached("Unknown client identifier type.");
1414 }
1415
1416 return 0;
1417}
1418
294f129b
YW
1419static int dhcp4_configure_duid(Link *link) {
1420 assert(link);
1421
1422 if (!IN_SET(link->network->dhcp_client_identifier, DHCP_CLIENT_ID_DUID, DHCP_CLIENT_ID_DUID_ONLY))
1423 return 1;
1424
1425 return dhcp_configure_duid(link, link_get_dhcp4_duid(link));
1426}
1427
3def8850
YW
1428static int dhcp4_set_request_address(Link *link) {
1429 Address *a;
571eeba9
YW
1430
1431 assert(link);
3def8850
YW
1432 assert(link->network);
1433 assert(link->dhcp_client);
571eeba9 1434
3def8850 1435 if (!FLAGS_SET(link->network->keep_configuration, KEEP_CONFIGURATION_DHCP))
571eeba9
YW
1436 return 0;
1437
3def8850
YW
1438 SET_FOREACH(a, link->addresses_foreign) {
1439 if (a->family != AF_INET)
1440 continue;
1441 if (link_address_is_dynamic(link, a))
1442 break;
1443 }
571eeba9 1444
3def8850
YW
1445 if (!a)
1446 return 0;
571eeba9 1447
5f016e32
YW
1448 log_link_debug(link, "DHCP4 CLIENT: requesting " IPV4_ADDRESS_FMT_STR, IPV4_ADDRESS_FMT_VAL(a->in_addr.in));
1449
3def8850 1450 return sd_dhcp_client_set_request_address(link->dhcp_client, &a->in_addr.in);
571eeba9
YW
1451}
1452
e70eca9b
VM
1453static bool link_needs_dhcp_broadcast(Link *link) {
1454 const char *val;
1455 int r;
1456
1457 assert(link);
1458 assert(link->network);
1459
1460 /* Return the setting in DHCP[4].RequestBroadcast if specified. Otherwise return the device property
1461 * ID_NET_DHCP_BROADCAST setting, which may be set for interfaces requiring that the DHCPOFFER message
1462 * is being broadcast because they can't handle unicast messages while not fully configured.
1463 * If neither is set or a failure occurs, return false, which is the default for this flag.
1464 */
1465 r = link->network->dhcp_broadcast;
1466 if (r < 0 && link->sd_device && sd_device_get_property_value(link->sd_device, "ID_NET_DHCP_BROADCAST", &val) >= 0) {
1467 r = parse_boolean(val);
1468 if (r < 0)
1469 log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to parse ID_NET_DHCP_BROADCAST, ignoring: %m");
1470 else
1471 log_link_debug(link, "DHCP4 CLIENT: Detected ID_NET_DHCP_BROADCAST='%d'.", r);
1472
1473 }
1474 return r == true;
1475}
1476
3c9b8860 1477int dhcp4_configure(Link *link) {
cb29c156 1478 sd_dhcp_option *send_option;
5bc945be 1479 void *request_options;
3c9b8860
TG
1480 int r;
1481
1482 assert(link);
1483 assert(link->network);
2ffd6d73
YW
1484
1485 if (!link_dhcp4_enabled(link))
1486 return 0;
1487
bc9e40c9
YW
1488 if (link->dhcp_client)
1489 return -EBUSY; /* Already configured. */
3c9b8860 1490
294f129b
YW
1491 r = dhcp4_configure_duid(link);
1492 if (r <= 0)
1493 return r;
1494
bc9e40c9
YW
1495 r = sd_dhcp_client_new(&link->dhcp_client, link->network->dhcp_anonymize);
1496 if (r < 0)
1497 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to allocate DHCP4 client: %m");
1498
1499 r = sd_dhcp_client_attach_event(link->dhcp_client, link->manager->event, 0);
1500 if (r < 0)
1501 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to attach event to DHCP4 client: %m");
3c9b8860 1502
76253e73 1503 r = sd_dhcp_client_set_mac(link->dhcp_client,
b8162cd2 1504 link->hw_addr.addr.bytes,
14b66dbc
TR
1505 link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
1506 link->hw_addr.length, link->iftype);
3c9b8860 1507 if (r < 0)
62f12d75 1508 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MAC address: %m");
3c9b8860 1509
2f8e7633 1510 r = sd_dhcp_client_set_ifindex(link->dhcp_client, link->ifindex);
3c9b8860 1511 if (r < 0)
62f12d75 1512 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set ifindex: %m");
3c9b8860
TG
1513
1514 r = sd_dhcp_client_set_callback(link->dhcp_client, dhcp4_handler, link);
1515 if (r < 0)
62f12d75 1516 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set callback: %m");
3c9b8860 1517
e70eca9b 1518 r = sd_dhcp_client_set_request_broadcast(link->dhcp_client, link_needs_dhcp_broadcast(link));
3c9b8860 1519 if (r < 0)
62f12d75 1520 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for broadcast: %m");
3c9b8860 1521
62f12d75 1522 if (link->mtu > 0) {
3c9b8860
TG
1523 r = sd_dhcp_client_set_mtu(link->dhcp_client, link->mtu);
1524 if (r < 0)
62f12d75 1525 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MTU: %m");
3c9b8860
TG
1526 }
1527
a83bda05
YW
1528 if (!link->network->dhcp_anonymize) {
1529 if (link->network->dhcp_use_mtu) {
1530 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_INTERFACE_MTU);
1531 if (r < 0)
1532 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for MTU: %m");
1533 }
3c9b8860 1534
a83bda05
YW
1535 if (link->network->dhcp_use_routes) {
1536 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_STATIC_ROUTE);
1537 if (r < 0)
1538 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for static route: %m");
1f6860d9 1539
a83bda05
YW
1540 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_CLASSLESS_STATIC_ROUTE);
1541 if (r < 0)
1542 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for classless static route: %m");
1543 }
3c9b8860 1544
a83bda05
YW
1545 if (link->network->dhcp_use_domains != DHCP_USE_DOMAINS_NO) {
1546 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_DOMAIN_SEARCH_LIST);
1547 if (r < 0)
1548 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for domain search list: %m");
1549 }
150d3b8e 1550
a83bda05
YW
1551 if (link->network->dhcp_use_ntp) {
1552 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NTP_SERVER);
1553 if (r < 0)
1554 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for NTP server: %m");
1555 }
4b7b5abb 1556
a83bda05
YW
1557 if (link->network->dhcp_use_sip) {
1558 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_SIP_SERVER);
1559 if (r < 0)
1560 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for SIP server: %m");
1561 }
299d578f 1562
a83bda05
YW
1563 if (link->network->dhcp_use_timezone) {
1564 r = sd_dhcp_client_set_request_option(link->dhcp_client, SD_DHCP_OPTION_NEW_TZDB_TIMEZONE);
1565 if (r < 0)
1566 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for timezone: %m");
1567 }
8eb9058d 1568
a83bda05
YW
1569 SET_FOREACH(request_options, link->network->dhcp_request_options) {
1570 uint32_t option = PTR_TO_UINT32(request_options);
5bc945be 1571
a83bda05
YW
1572 r = sd_dhcp_client_set_request_option(link->dhcp_client, option);
1573 if (r < 0)
1574 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set request flag for '%u': %m", option);
1575 }
7354900d 1576
a83bda05
YW
1577 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_options) {
1578 r = sd_dhcp_client_add_option(link->dhcp_client, send_option);
1579 if (r == -EEXIST)
1580 continue;
1581 if (r < 0)
1582 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
1583 }
cb29c156 1584
a83bda05
YW
1585 ORDERED_HASHMAP_FOREACH(send_option, link->network->dhcp_client_send_vendor_options) {
1586 r = sd_dhcp_client_add_vendor_option(link->dhcp_client, send_option);
1587 if (r == -EEXIST)
1588 continue;
1589 if (r < 0)
1590 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set send option: %m");
1591 }
3c9b8860 1592
a83bda05 1593 r = dhcp4_set_hostname(link);
3c9b8860 1594 if (r < 0)
a83bda05 1595 return r;
3c9b8860 1596
a83bda05
YW
1597 if (link->network->dhcp_vendor_class_identifier) {
1598 r = sd_dhcp_client_set_vendor_class_identifier(link->dhcp_client,
1599 link->network->dhcp_vendor_class_identifier);
1600 if (r < 0)
1601 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set vendor class identifier: %m");
1602 }
7b8d23a9 1603
a83bda05
YW
1604 if (link->network->dhcp_mudurl) {
1605 r = sd_dhcp_client_set_mud_url(link->dhcp_client, link->network->dhcp_mudurl);
1606 if (r < 0)
1607 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set MUD URL: %m");
1608 }
1609
1610 if (link->network->dhcp_user_class) {
1611 r = sd_dhcp_client_set_user_class(link->dhcp_client, link->network->dhcp_user_class);
1612 if (r < 0)
1613 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set user class: %m");
1614 }
af1c0de0
SS
1615 }
1616
62f12d75 1617 if (link->network->dhcp_client_port > 0) {
9faed222
SS
1618 r = sd_dhcp_client_set_client_port(link->dhcp_client, link->network->dhcp_client_port);
1619 if (r < 0)
62f12d75 1620 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set listen port: %m");
9faed222
SS
1621 }
1622
715cedfb
SS
1623 if (link->network->dhcp_max_attempts > 0) {
1624 r = sd_dhcp_client_set_max_attempts(link->dhcp_client, link->network->dhcp_max_attempts);
1625 if (r < 0)
62f12d75 1626 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set max attempts: %m");
715cedfb
SS
1627 }
1628
db5756f3
YW
1629 if (link->network->dhcp_ip_service_type > 0) {
1630 r = sd_dhcp_client_set_service_type(link->dhcp_client, link->network->dhcp_ip_service_type);
afe42aef 1631 if (r < 0)
62f12d75 1632 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set IP service type: %m");
afe42aef 1633 }
0f3ff4ea 1634
d6463307
SS
1635 if (link->network->dhcp_fallback_lease_lifetime > 0) {
1636 r = sd_dhcp_client_set_fallback_lease_lifetime(link->dhcp_client, link->network->dhcp_fallback_lease_lifetime);
1637 if (r < 0)
62f12d75 1638 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed set to lease lifetime: %m");
d6463307
SS
1639 }
1640
3def8850
YW
1641 r = dhcp4_set_request_address(link);
1642 if (r < 0)
62f12d75 1643 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to set initial DHCPv4 address: %m");
3def8850 1644
10fa21c0
YW
1645 r = dhcp4_configure_dad(link);
1646 if (r < 0)
62f12d75 1647 return log_link_warning_errno(link, r, "DHCP4 CLIENT: Failed to configure service type: %m");
0f3ff4ea
SS
1648
1649 return dhcp4_set_client_identifier(link);
3c9b8860 1650}
ca5ad760 1651
d947f7f9
YW
1652int dhcp4_update_mac(Link *link) {
1653 int r;
1654
1655 assert(link);
1656
1657 if (!link->dhcp_client)
1658 return 0;
1659
14b66dbc
TR
1660 r = sd_dhcp_client_set_mac(link->dhcp_client, link->hw_addr.addr.bytes,
1661 link->bcast_addr.length > 0 ? link->bcast_addr.addr.bytes : NULL,
1662 link->hw_addr.length, link->iftype);
d947f7f9
YW
1663 if (r < 0)
1664 return r;
1665
1666 r = dhcp4_set_client_identifier(link);
1667 if (r < 0)
1668 return r;
1669
54312274
YW
1670 r = dhcp4_dad_update_mac(link);
1671 if (r < 0)
1672 return r;
1673
d947f7f9
YW
1674 return 0;
1675}
1676
294f129b
YW
1677int dhcp4_start(Link *link) {
1678 assert(link);
1679
1680 if (!link->dhcp_client)
1681 return 0;
1682
1683 if (sd_dhcp_client_is_running(link->dhcp_client) > 0)
1684 return 0;
1685
1686 log_link_debug(link, "Acquiring DHCPv4 lease");
1687
1688 return sd_dhcp_client_start(link->dhcp_client);
1689}
1690
ca5ad760
YW
1691int config_parse_dhcp_max_attempts(
1692 const char *unit,
1693 const char *filename,
1694 unsigned line,
1695 const char *section,
1696 unsigned section_line,
1697 const char *lvalue,
1698 int ltype,
1699 const char *rvalue,
1700 void *data,
1701 void *userdata) {
1702
1703 Network *network = data;
1704 uint64_t a;
1705 int r;
1706
1707 assert(network);
1708 assert(lvalue);
1709 assert(rvalue);
1710
1711 if (isempty(rvalue)) {
1712 network->dhcp_max_attempts = 0;
1713 return 0;
1714 }
1715
1716 if (streq(rvalue, "infinity")) {
f5fbe71d 1717 network->dhcp_max_attempts = UINT64_MAX;
ca5ad760
YW
1718 return 0;
1719 }
1720
1721 r = safe_atou64(rvalue, &a);
1722 if (r < 0) {
d96edb2c 1723 log_syntax(unit, LOG_WARNING, filename, line, r,
ca5ad760
YW
1724 "Failed to parse DHCP maximum attempts, ignoring: %s", rvalue);
1725 return 0;
1726 }
1727
1728 if (a == 0) {
d96edb2c 1729 log_syntax(unit, LOG_WARNING, filename, line, 0,
ca5ad760
YW
1730 "%s= must be positive integer or 'infinity', ignoring: %s", lvalue, rvalue);
1731 return 0;
1732 }
1733
1734 network->dhcp_max_attempts = a;
1735
1736 return 0;
1737}
1738
98ebef62 1739int config_parse_dhcp_acl_ip_address(
ca5ad760
YW
1740 const char *unit,
1741 const char *filename,
1742 unsigned line,
1743 const char *section,
1744 unsigned section_line,
1745 const char *lvalue,
1746 int ltype,
1747 const char *rvalue,
1748 void *data,
1749 void *userdata) {
1750
1751 Network *network = data;
98ebef62 1752 Set **acl;
ca5ad760
YW
1753 int r;
1754
1755 assert(filename);
1756 assert(lvalue);
1757 assert(rvalue);
1758 assert(data);
1759
98ebef62
SS
1760 acl = STR_IN_SET(lvalue, "DenyList", "BlackList") ? &network->dhcp_deny_listed_ip : &network->dhcp_allow_listed_ip;
1761
ca5ad760 1762 if (isempty(rvalue)) {
98ebef62 1763 *acl = set_free(*acl);
ca5ad760
YW
1764 return 0;
1765 }
1766
de7fef4b 1767 for (const char *p = rvalue;;) {
ca5ad760
YW
1768 _cleanup_free_ char *n = NULL;
1769 union in_addr_union ip;
1770
1771 r = extract_first_word(&p, &n, NULL, 0);
d96edb2c
YW
1772 if (r == -ENOMEM)
1773 return log_oom();
ca5ad760 1774 if (r < 0) {
d96edb2c 1775 log_syntax(unit, LOG_WARNING, filename, line, r,
98ebef62
SS
1776 "Failed to parse DHCP '%s=' IP address, ignoring assignment: %s",
1777 lvalue, rvalue);
ca5ad760
YW
1778 return 0;
1779 }
1780 if (r == 0)
1781 return 0;
1782
1783 r = in_addr_from_string(AF_INET, n, &ip);
1784 if (r < 0) {
d96edb2c 1785 log_syntax(unit, LOG_WARNING, filename, line, r,
98ebef62 1786 "DHCP '%s=' IP address is invalid, ignoring assignment: %s", lvalue, n);
ca5ad760
YW
1787 continue;
1788 }
1789
98ebef62 1790 r = set_ensure_put(acl, NULL, UINT32_TO_PTR(ip.in.s_addr));
ca5ad760 1791 if (r < 0)
d96edb2c 1792 log_syntax(unit, LOG_WARNING, filename, line, r,
98ebef62 1793 "Failed to store DHCP '%s=' IP address '%s', ignoring assignment: %m", lvalue, n);
ca5ad760 1794 }
ca5ad760
YW
1795}
1796
a75b2117
SS
1797int config_parse_dhcp_ip_service_type(
1798 const char *unit,
1799 const char *filename,
1800 unsigned line,
1801 const char *section,
1802 unsigned section_line,
1803 const char *lvalue,
1804 int ltype,
1805 const char *rvalue,
1806 void *data,
1807 void *userdata) {
1808
1809 assert(filename);
1810 assert(lvalue);
1811 assert(rvalue);
1812
1813 if (streq(rvalue, "CS4"))
1814 *((int *)data) = IPTOS_CLASS_CS4;
1815 else if (streq(rvalue, "CS6"))
1816 *((int *)data) = IPTOS_CLASS_CS6;
1817 else
1818 log_syntax(unit, LOG_WARNING, filename, line, 0,
1819 "Failed to parse IPServiceType type '%s', ignoring.", rvalue);
1820
1821 return 0;
1822}
1823
7b8d23a9
SS
1824int config_parse_dhcp_mud_url(
1825 const char *unit,
1826 const char *filename,
1827 unsigned line,
1828 const char *section,
1829 unsigned section_line,
1830 const char *lvalue,
1831 int ltype,
1832 const char *rvalue,
1833 void *data,
1834 void *userdata) {
1835
1836 _cleanup_free_ char *unescaped = NULL;
1837 Network *network = data;
1838 int r;
1839
1840 assert(filename);
1841 assert(lvalue);
1842 assert(rvalue);
1843
1844 if (isempty(rvalue)) {
1845 network->dhcp_mudurl = mfree(network->dhcp_mudurl);
1846 return 0;
1847 }
1848
1849 r = cunescape(rvalue, 0, &unescaped);
1850 if (r < 0) {
d96edb2c 1851 log_syntax(unit, LOG_WARNING, filename, line, r,
7b8d23a9
SS
1852 "Failed to Failed to unescape MUD URL, ignoring: %s", rvalue);
1853 return 0;
1854 }
1855
1856 if (!http_url_is_valid(unescaped) || strlen(unescaped) > 255) {
d96edb2c 1857 log_syntax(unit, LOG_WARNING, filename, line, 0,
7b8d23a9
SS
1858 "Failed to parse MUD URL '%s', ignoring: %m", rvalue);
1859
1860 return 0;
1861 }
1862
1863 return free_and_strdup_warn(&network->dhcp_mudurl, unescaped);
1864}
1865
d6463307
SS
1866int config_parse_dhcp_fallback_lease_lifetime(const char *unit,
1867 const char *filename,
1868 unsigned line,
1869 const char *section,
1870 unsigned section_line,
1871 const char *lvalue,
1872 int ltype,
1873 const char *rvalue,
1874 void *data,
1875 void *userdata) {
1876 Network *network = userdata;
d2735796 1877 uint32_t k;
d6463307
SS
1878
1879 assert(filename);
1880 assert(section);
1881 assert(lvalue);
1882 assert(rvalue);
1883 assert(data);
1884
1885 if (isempty(rvalue)) {
1886 network->dhcp_fallback_lease_lifetime = 0;
1887 return 0;
1888 }
1889
1890 /* We accept only "forever" or "infinity". */
1891 if (STR_IN_SET(rvalue, "forever", "infinity"))
1892 k = CACHE_INFO_INFINITY_LIFE_TIME;
1893 else {
d96edb2c 1894 log_syntax(unit, LOG_WARNING, filename, line, 0,
d6463307
SS
1895 "Invalid LeaseLifetime= value, ignoring: %s", rvalue);
1896 return 0;
1897 }
1898
1899 network->dhcp_fallback_lease_lifetime = k;
1900
1901 return 0;
1902}
1903
ca5ad760
YW
1904static const char* const dhcp_client_identifier_table[_DHCP_CLIENT_ID_MAX] = {
1905 [DHCP_CLIENT_ID_MAC] = "mac",
1906 [DHCP_CLIENT_ID_DUID] = "duid",
1907 [DHCP_CLIENT_ID_DUID_ONLY] = "duid-only",
1908};
1909
1910DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING(dhcp_client_identifier, DHCPClientIdentifier);
1911DEFINE_CONFIG_PARSE_ENUM(config_parse_dhcp_client_identifier, dhcp_client_identifier, DHCPClientIdentifier,
1912 "Failed to parse client identifier type");