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