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