]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp-server.c
Revert "mkosi: turn off qemu headless mode"
[thirdparty/systemd.git] / src / network / networkd-dhcp-server.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
8fcf1d61 2
5ae0fb7f
YW
3#include <netinet/in.h>
4#include <linux/if_arp.h>
5#include <linux/if.h>
6
8fcf1d61
YW
7#include "sd-dhcp-server.h"
8
dd1d3060
MAL
9#include "fd-util.h"
10#include "fileio.h"
093e3533 11#include "networkd-address.h"
a95e9306 12#include "networkd-dhcp-server-bus.h"
c517a49b 13#include "networkd-dhcp-server-static-lease.h"
14#include "networkd-dhcp-server.h"
8fcf1d61
YW
15#include "networkd-link.h"
16#include "networkd-manager.h"
17#include "networkd-network.h"
1d28a3cf 18#include "networkd-queue.h"
564ca984 19#include "parse-util.h"
dd1d3060 20#include "socket-netlink.h"
564ca984
SS
21#include "string-table.h"
22#include "string-util.h"
dd1d3060 23#include "strv.h"
8fcf1d61 24
5ae0fb7f
YW
25static bool link_dhcp4_server_enabled(Link *link) {
26 assert(link);
27
28 if (link->flags & IFF_LOOPBACK)
29 return false;
30
31 if (!link->network)
32 return false;
33
5ae0fb7f
YW
34 if (link->iftype == ARPHRD_CAN)
35 return false;
36
37 return link->network->dhcp_server;
38}
39
0017ba31
YW
40void network_adjust_dhcp_server(Network *network) {
41 assert(network);
42
43 if (!network->dhcp_server)
44 return;
45
46 if (network->bond) {
47 log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
48 network->filename);
49 network->dhcp_server = false;
50 return;
51 }
52
53 if (!in4_addr_is_set(&network->dhcp_server_address)) {
54 Address *address;
55 bool have = false;
56
57 ORDERED_HASHMAP_FOREACH(address, network->addresses_by_section) {
58 if (section_is_invalid(address->section))
59 continue;
60 if (address->family == AF_INET &&
61 !in4_addr_is_localhost(&address->in_addr.in) &&
62 in4_addr_is_null(&address->in_addr_peer.in)) {
63 have = true;
64 break;
65 }
66 }
67 if (!have) {
68 log_warning("%s: DHCPServer= is enabled, but no static address configured. "
69 "Disabling DHCP server.",
70 network->filename);
71 network->dhcp_server = false;
72 return;
73 }
74 }
75}
76
77static int link_find_dhcp_server_address(Link *link, Address **ret) {
8fcf1d61
YW
78 Address *address;
79
80 assert(link);
81 assert(link->network);
82
0017ba31
YW
83 /* If ServerAddress= is specified, then use the address. */
84 if (in4_addr_is_set(&link->network->dhcp_server_address))
85 return link_get_ipv4_address(link, &link->network->dhcp_server_address,
86 link->network->dhcp_server_address_prefixlen, ret);
8fcf1d61 87
0017ba31
YW
88 /* If not, then select one from static addresses. */
89 SET_FOREACH(address, link->static_addresses)
90 if (address->family == AF_INET &&
91 !in4_addr_is_localhost(&address->in_addr.in) &&
92 in4_addr_is_null(&address->in_addr_peer.in)) {
93 *ret = address;
94 return 0;
95 }
8fcf1d61 96
0017ba31 97 return -ENOENT;
8fcf1d61
YW
98}
99
165d7c5c
YW
100static int dhcp_server_find_uplink(Link *link, Link **ret) {
101 assert(link);
102
103 if (link->network->dhcp_server_uplink_name)
104 return link_get_by_name(link->manager, link->network->dhcp_server_uplink_name, ret);
105
106 if (link->network->dhcp_server_uplink_index > 0)
6eab614d 107 return link_get_by_index(link->manager, link->network->dhcp_server_uplink_index, ret);
165d7c5c 108
63295b42 109 if (link->network->dhcp_server_uplink_index == UPLINK_INDEX_AUTO) {
165d7c5c
YW
110 /* It is not necessary to propagate error in automatic selection. */
111 if (manager_find_uplink(link->manager, AF_INET, link, ret) < 0)
112 *ret = NULL;
113 return 0;
114 }
115
116 *ret = NULL;
117 return 0;
118}
119
2a71d57f
LP
120static int link_push_uplink_to_dhcp_server(
121 Link *link,
2324fd3a 122 sd_dhcp_lease_server_type_t what,
2a71d57f
LP
123 sd_dhcp_server *s) {
124
8fcf1d61 125 _cleanup_free_ struct in_addr *addresses = NULL;
2a71d57f 126 bool use_dhcp_lease_data = true;
319a4f4b 127 size_t n_addresses = 0;
8fcf1d61 128
2a71d57f 129 assert(link);
8fcf1d61 130
2a71d57f
LP
131 if (!link->network)
132 return 0;
133 assert(link->network);
8fcf1d61 134
2a71d57f 135 log_link_debug(link, "Copying %s from link", dhcp_lease_server_type_to_string(what));
8fcf1d61 136
2a71d57f 137 switch (what) {
8fcf1d61 138
2a71d57f
LP
139 case SD_DHCP_LEASE_DNS:
140 /* For DNS we have a special case. We the data configured explicitly locally along with the
141 * data from the DHCP lease. */
8fcf1d61 142
2a71d57f
LP
143 for (unsigned i = 0; i < link->network->n_dns; i++) {
144 struct in_addr ia;
8fcf1d61 145
2a71d57f 146 /* Only look for IPv4 addresses */
e77bd3fd 147 if (link->network->dns[i]->family != AF_INET)
2a71d57f 148 continue;
8fcf1d61 149
e77bd3fd 150 ia = link->network->dns[i]->address.in;
2a71d57f
LP
151
152 /* Never propagate obviously borked data */
153 if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
154 continue;
155
319a4f4b 156 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
8fcf1d61
YW
157 return log_oom();
158
2a71d57f 159 addresses[n_addresses++] = ia;
8fcf1d61 160 }
8fcf1d61 161
2a71d57f
LP
162 use_dhcp_lease_data = link->network->dhcp_use_dns;
163 break;
8fcf1d61 164
2a71d57f
LP
165 case SD_DHCP_LEASE_NTP: {
166 char **i;
8fcf1d61 167
2a71d57f
LP
168 /* For NTP things are similar, but for NTP hostnames can be configured too, which we cannot
169 * propagate via DHCP. Hence let's only propagate those which are IP addresses. */
284e8fd0 170
2a71d57f
LP
171 STRV_FOREACH(i, link->network->ntp) {
172 union in_addr_union ia;
284e8fd0 173
2a71d57f
LP
174 if (in_addr_from_string(AF_INET, *i, &ia) < 0)
175 continue;
284e8fd0 176
2a71d57f
LP
177 /* Never propagate obviously borked data */
178 if (in4_addr_is_null(&ia.in) || in4_addr_is_localhost(&ia.in))
179 continue;
284e8fd0 180
319a4f4b 181 if (!GREEDY_REALLOC(addresses, n_addresses + 1))
2a71d57f 182 return log_oom();
284e8fd0 183
2a71d57f
LP
184 addresses[n_addresses++] = ia.in;
185 }
284e8fd0 186
2a71d57f 187 use_dhcp_lease_data = link->network->dhcp_use_ntp;
24e6f458 188 break;
2a71d57f 189 }
284e8fd0 190
ddb82ec2 191 case SD_DHCP_LEASE_SIP:
2a71d57f
LP
192
193 /* For SIP we don't allow explicit, local configuration, but there's control whether to use the data */
194 use_dhcp_lease_data = link->network->dhcp_use_sip;
24e6f458 195 break;
284e8fd0 196
2a71d57f
LP
197 case SD_DHCP_LEASE_POP3:
198 case SD_DHCP_LEASE_SMTP:
ddb82ec2 199 case SD_DHCP_LEASE_LPR:
2a71d57f
LP
200 /* For the other server types we currently do not allow local configuration of server data,
201 * since there are typically no local consumers of the data. */
c4e585a3 202 break;
d361b373 203
24e6f458 204 default:
04499a70 205 assert_not_reached();
f6269fe7
SS
206 }
207
2a71d57f 208 if (use_dhcp_lease_data && link->dhcp_lease) {
24e6f458 209 const struct in_addr *da;
f6269fe7 210
a2706075 211 int n = sd_dhcp_lease_get_servers(link->dhcp_lease, what, &da);
f6269fe7 212 if (n > 0) {
319a4f4b 213 if (!GREEDY_REALLOC(addresses, n_addresses + n))
f6269fe7
SS
214 return log_oom();
215
2a71d57f
LP
216 for (int j = 0; j < n; j++)
217 if (in4_addr_is_non_local(&da[j]))
218 addresses[n_addresses++] = da[j];
f6269fe7
SS
219 }
220 }
221
222 if (n_addresses <= 0)
223 return 0;
224
24e6f458 225 return sd_dhcp_server_set_servers(s, what, addresses, n_addresses);
299d578f
SS
226}
227
319a4f4b
LP
228static int dhcp4_server_parse_dns_server_string_and_warn(
229 const char *string,
230 struct in_addr **addresses,
231 size_t *n_addresses) {
232
dd1d3060
MAL
233 for (;;) {
234 _cleanup_free_ char *word = NULL, *server_name = NULL;
235 union in_addr_union address;
236 int family, r, ifindex = 0;
237
238 r = extract_first_word(&string, &word, NULL, 0);
239 if (r < 0)
240 return r;
241 if (r == 0)
242 break;
243
244 r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
245 if (r < 0) {
246 log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring: %m", word);
247 continue;
248 }
249
250 /* Only look for IPv4 addresses */
251 if (family != AF_INET)
252 continue;
253
254 /* Never propagate obviously borked data */
255 if (in4_addr_is_null(&address.in) || in4_addr_is_localhost(&address.in))
256 continue;
257
319a4f4b 258 if (!GREEDY_REALLOC(*addresses, *n_addresses + 1))
dd1d3060
MAL
259 return log_oom();
260
261 (*addresses)[(*n_addresses)++] = address.in;
262 }
263
264 return 0;
265}
266
267static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
268 _cleanup_free_ struct in_addr *addresses = NULL;
dd1d3060 269 _cleanup_fclose_ FILE *f = NULL;
319a4f4b 270 size_t n_addresses = 0;
dd1d3060
MAL
271 int n = 0, r;
272
273 f = fopen(PRIVATE_UPLINK_RESOLV_CONF, "re");
274 if (!f) {
275 if (errno == ENOENT)
276 return 0;
277
278 return log_warning_errno(errno, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF ": %m");
279 }
280
281 for (;;) {
282 _cleanup_free_ char *line = NULL;
283 const char *a;
284 char *l;
285
286 r = read_line(f, LONG_LINE_MAX, &line);
287 if (r < 0)
288 return log_error_errno(r, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF ": %m");
289 if (r == 0)
290 break;
291
292 n++;
293
294 l = strstrip(line);
295 if (IN_SET(*l, '#', ';', 0))
296 continue;
297
298 a = first_word(l, "nameserver");
299 if (!a)
300 continue;
301
319a4f4b 302 r = dhcp4_server_parse_dns_server_string_and_warn(a, &addresses, &n_addresses);
dd1d3060
MAL
303 if (r < 0)
304 log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
305 }
306
307 if (n_addresses <= 0)
308 return 0;
309
310 return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
311}
312
1d28a3cf 313static int dhcp4_server_configure(Link *link) {
8fcf1d61 314 bool acquired_uplink = false;
461dbb2f 315 sd_dhcp_option *p;
c517a49b 316 DHCPStaticLease *static_lease;
564ca984
SS
317 Link *uplink = NULL;
318 Address *address;
11c38d3e 319 bool bind_to_interface;
8fcf1d61
YW
320 int r;
321
5ae0fb7f
YW
322 assert(link);
323
1d28a3cf 324 log_link_debug(link, "Configuring DHCP Server.");
5ae0fb7f 325
1d28a3cf
YW
326 if (link->dhcp_server)
327 return -EBUSY;
5ae0fb7f 328
1d28a3cf
YW
329 r = sd_dhcp_server_new(&link->dhcp_server, link->ifindex);
330 if (r < 0)
331 return r;
5ae0fb7f 332
1d28a3cf
YW
333 r = sd_dhcp_server_attach_event(link->dhcp_server, link->manager->event, 0);
334 if (r < 0)
335 return r;
5ae0fb7f 336
a95e9306
LK
337 r = sd_dhcp_server_set_callback(link->dhcp_server, dhcp_server_callback, link);
338 if (r < 0)
339 return log_link_warning_errno(link, r, "Failed to set callback for DHCPv4 server instance: %m");
340
0017ba31
YW
341 r = link_find_dhcp_server_address(link, &address);
342 if (r < 0)
343 return log_link_error_errno(link, r, "Failed to find suitable address for DHCPv4 server instance: %m");
8fcf1d61
YW
344
345 /* use the server address' subnet as the pool */
346 r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
347 link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size);
348 if (r < 0)
c00c3b64 349 return log_link_error_errno(link, r, "Failed to configure address pool for DHCPv4 server instance: %m");
8fcf1d61
YW
350
351 /* TODO:
352 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
353 if (r < 0)
354 return r;
355 */
356
357 if (link->network->dhcp_server_max_lease_time_usec > 0) {
358 r = sd_dhcp_server_set_max_lease_time(link->dhcp_server,
359 DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC));
360 if (r < 0)
c00c3b64 361 return log_link_error_errno(link, r, "Failed to set maximum lease time for DHCPv4 server instance: %m");
8fcf1d61
YW
362 }
363
364 if (link->network->dhcp_server_default_lease_time_usec > 0) {
365 r = sd_dhcp_server_set_default_lease_time(link->dhcp_server,
366 DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC));
367 if (r < 0)
c00c3b64 368 return log_link_error_errno(link, r, "Failed to set default lease time for DHCPv4 server instance: %m");
8fcf1d61
YW
369 }
370
2324fd3a 371 for (sd_dhcp_lease_server_type_t type = 0; type < _SD_DHCP_LEASE_SERVER_TYPE_MAX; type ++) {
2a71d57f
LP
372
373 if (!link->network->dhcp_server_emit[type].emit)
374 continue;
375
376 if (link->network->dhcp_server_emit[type].n_addresses > 0)
377 /* Explicitly specified servers to emit */
378 r = sd_dhcp_server_set_servers(
379 link->dhcp_server,
380 type,
381 link->network->dhcp_server_emit[type].addresses,
382 link->network->dhcp_server_emit[type].n_addresses);
383 else {
384 /* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */
385 if (!acquired_uplink) {
165d7c5c 386 (void) dhcp_server_find_uplink(link, &uplink);
2a71d57f
LP
387 acquired_uplink = true;
388 }
389
390 if (uplink && uplink->network)
391 r = link_push_uplink_to_dhcp_server(uplink, type, link->dhcp_server);
392 else if (type == SD_DHCP_LEASE_DNS)
393 r = dhcp4_server_set_dns_from_resolve_conf(link);
24e6f458 394 else {
2a71d57f
LP
395 log_link_debug(link,
396 "Not emitting %s on link, couldn't find suitable uplink.",
397 dhcp_lease_server_type_to_string(type));
398 continue;
24e6f458 399 }
299d578f 400 }
284e8fd0 401
2a71d57f
LP
402 if (r < 0)
403 log_link_warning_errno(link, r,
404 "Failed to set %s for DHCP server, ignoring: %m",
405 dhcp_lease_server_type_to_string(type));
406 }
407
8fcf1d61
YW
408 r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
409 if (r < 0)
a0fa3ef7 410 return log_link_error_errno(link, r, "Failed to set router emission for DHCP server: %m");
8fcf1d61 411
c95df587
YA
412 r = sd_dhcp_server_set_relay_target(link->dhcp_server, &link->network->dhcp_server_relay_target);
413 if (r < 0)
414 return log_link_error_errno(link, r, "Failed to set relay target for DHCP server: %m");
415
11c38d3e
YA
416 bind_to_interface = sd_dhcp_server_is_in_relay_mode(link->dhcp_server) ? false : link->network->dhcp_server_bind_to_interface;
417 r = sd_dhcp_server_set_bind_to_interface(link->dhcp_server, bind_to_interface);
418 if (r < 0)
419 return log_link_error_errno(link, r, "Failed to set interface binding for DHCP server: %m");
420
421 r = sd_dhcp_server_set_relay_agent_information(link->dhcp_server, link->network->dhcp_server_relay_agent_circuit_id, link->network->dhcp_server_relay_agent_remote_id);
422 if (r < 0)
423 return log_link_error_errno(link, r, "Failed to set agent circuit/remote id for DHCP server: %m");
424
8fcf1d61
YW
425 if (link->network->dhcp_server_emit_timezone) {
426 _cleanup_free_ char *buffer = NULL;
7b5018ca 427 const char *tz = NULL;
8fcf1d61
YW
428
429 if (link->network->dhcp_server_timezone)
430 tz = link->network->dhcp_server_timezone;
431 else {
432 r = get_timezone(&buffer);
433 if (r < 0)
7b5018ca 434 log_link_warning_errno(link, r, "Failed to determine timezone, not sending timezone: %m");
435 else
436 tz = buffer;
8fcf1d61
YW
437 }
438
7b5018ca 439 if (tz) {
440 r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
441 if (r < 0)
442 return log_link_error_errno(link, r, "Failed to set timezone for DHCP server: %m");
443 }
8fcf1d61 444 }
564ca984 445
90e74a66 446 ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_options) {
461dbb2f 447 r = sd_dhcp_server_add_option(link->dhcp_server, p);
564ca984
SS
448 if (r == -EEXIST)
449 continue;
450 if (r < 0)
c00c3b64 451 return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
564ca984
SS
452 }
453
90e74a66 454 ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_vendor_options) {
7354900d
DW
455 r = sd_dhcp_server_add_vendor_option(link->dhcp_server, p);
456 if (r == -EEXIST)
457 continue;
458 if (r < 0)
459 return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
460 }
461
c517a49b 462 HASHMAP_FOREACH(static_lease, link->network->dhcp_static_leases_by_section) {
463 r = sd_dhcp_server_set_static_lease(link->dhcp_server, &static_lease->address, static_lease->client_id, static_lease->client_id_size);
464 if (r < 0)
465 return log_link_error_errno(link, r, "Failed to set DHCPv4 static lease for DHCP server: %m");
466 }
467
ab486ef4
YW
468 r = sd_dhcp_server_start(link->dhcp_server);
469 if (r < 0)
470 return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
5ae0fb7f 471
ab486ef4 472 log_link_debug(link, "Offering DHCPv4 leases");
8fcf1d61 473
1d28a3cf
YW
474 return 1;
475}
476
477int link_request_dhcp_server(Link *link) {
478 assert(link);
479
480 if (!link_dhcp4_server_enabled(link))
481 return 0;
482
483 if (link->dhcp_server)
484 return 0;
485
486 log_link_debug(link, "Requesting DHCP server.");
487 return link_queue_request(link, REQUEST_TYPE_DHCP_SERVER, NULL, false, NULL, NULL, NULL);
488}
489
490static bool dhcp_server_is_ready_to_configure(Link *link) {
165d7c5c 491 Link *uplink = NULL;
1d28a3cf
YW
492 Address *a;
493
494 assert(link);
495
496 if (!link->network)
497 return false;
498
499 if (!IN_SET(link->state, LINK_STATE_CONFIGURING, LINK_STATE_CONFIGURED))
500 return false;
501
baa95d22
YW
502 if (link->set_flags_messages > 0)
503 return false;
504
1d28a3cf
YW
505 if (!link_has_carrier(link))
506 return false;
507
508 if (link->address_remove_messages > 0)
509 return false;
510
511 if (!link->static_addresses_configured)
512 return false;
513
514 if (link_find_dhcp_server_address(link, &a) < 0)
515 return false;
516
517 if (!address_is_ready(a))
518 return false;
519
165d7c5c
YW
520 if (dhcp_server_find_uplink(link, &uplink) < 0)
521 return false;
522
523 if (uplink && !uplink->network)
524 return false;
525
1d28a3cf
YW
526 return true;
527}
528
529int request_process_dhcp_server(Request *req) {
530 assert(req);
531 assert(req->link);
532 assert(req->type == REQUEST_TYPE_DHCP_SERVER);
533
534 if (!dhcp_server_is_ready_to_configure(req->link))
535 return 0;
536
537 return dhcp4_server_configure(req->link);
8fcf1d61
YW
538}
539
11c38d3e
YA
540int config_parse_dhcp_server_relay_agent_suboption(
541 const char *unit,
542 const char *filename,
543 unsigned line,
544 const char *section,
545 unsigned section_line,
546 const char *lvalue,
547 int ltype,
548 const char *rvalue,
549 void *data,
550 void *userdata) {
551
552 char **suboption_value = data;
553 char* p;
554
555 assert(filename);
556 assert(lvalue);
557 assert(rvalue);
558
11c38d3e
YA
559 if (isempty(rvalue)) {
560 *suboption_value = mfree(*suboption_value);
561 return 0;
562 }
563
564 p = startswith(rvalue, "string:");
565 if (!p) {
566 log_syntax(unit, LOG_WARNING, filename, line, 0,
567 "Failed to parse %s=%s'. Invalid format, ignoring.", lvalue, rvalue);
568 return 0;
569 }
570 return free_and_strdup(suboption_value, empty_to_null(p));
571}
572
2a71d57f 573int config_parse_dhcp_server_emit(
8fcf1d61
YW
574 const char *unit,
575 const char *filename,
576 unsigned line,
2a71d57f
LP
577 const char *section,
578 unsigned section_line,
8fcf1d61 579 const char *lvalue,
2a71d57f 580 int ltype,
8fcf1d61 581 const char *rvalue,
2a71d57f
LP
582 void *data,
583 void *userdata) {
8fcf1d61 584
2a71d57f
LP
585 NetworkDHCPServerEmitAddress *emit = data;
586
587 assert(emit);
8fcf1d61
YW
588 assert(rvalue);
589
c1997a5b 590 for (const char *p = rvalue;;) {
8fcf1d61
YW
591 _cleanup_free_ char *w = NULL;
592 union in_addr_union a;
c1997a5b 593 int r;
8fcf1d61
YW
594
595 r = extract_first_word(&p, &w, NULL, 0);
596 if (r == -ENOMEM)
597 return log_oom();
598 if (r < 0) {
d96edb2c 599 log_syntax(unit, LOG_WARNING, filename, line, r,
8fcf1d61
YW
600 "Failed to extract word, ignoring: %s", rvalue);
601 return 0;
602 }
603 if (r == 0)
c1997a5b 604 return 0;
8fcf1d61
YW
605
606 r = in_addr_from_string(AF_INET, w, &a);
607 if (r < 0) {
d96edb2c 608 log_syntax(unit, LOG_WARNING, filename, line, r,
c1997a5b 609 "Failed to parse %s= address '%s', ignoring: %m", lvalue, w);
8fcf1d61
YW
610 continue;
611 }
612
2a71d57f 613 struct in_addr *m = reallocarray(emit->addresses, emit->n_addresses + 1, sizeof(struct in_addr));
8fcf1d61
YW
614 if (!m)
615 return log_oom();
616
2a71d57f
LP
617 emit->addresses = m;
618 emit->addresses[emit->n_addresses++] = a.in;
8fcf1d61 619 }
8fcf1d61 620}
0017ba31
YW
621
622int config_parse_dhcp_server_address(
623 const char *unit,
624 const char *filename,
625 unsigned line,
626 const char *section,
627 unsigned section_line,
628 const char *lvalue,
629 int ltype,
630 const char *rvalue,
631 void *data,
632 void *userdata) {
633
634 Network *network = userdata;
635 union in_addr_union a;
636 unsigned char prefixlen;
637 int r;
638
639 assert(filename);
640 assert(lvalue);
641 assert(rvalue);
642
643 if (isempty(rvalue)) {
644 network->dhcp_server_address = (struct in_addr) {};
645 network->dhcp_server_address_prefixlen = 0;
646 return 0;
647 }
648
649 r = in_addr_prefix_from_string(rvalue, AF_INET, &a, &prefixlen);
650 if (r < 0) {
651 log_syntax(unit, LOG_WARNING, filename, line, r,
652 "Failed to parse %s=, ignoring assignment: %s", lvalue, rvalue);
653 return 0;
654 }
655 if (in4_addr_is_null(&a.in) || in4_addr_is_localhost(&a.in)) {
656 log_syntax(unit, LOG_WARNING, filename, line, 0,
657 "DHCP server address cannot be the ANY address or a localhost address, "
658 "ignoring assignment: %s", rvalue);
659 return 0;
660 }
661
662 network->dhcp_server_address = a.in;
663 network->dhcp_server_address_prefixlen = prefixlen;
664 return 0;
665}