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