1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <linux/if_arp.h>
4 #include <netinet/in.h>
6 #include "sd-dhcp-server.h"
8 #include "conf-parser.h"
9 #include "dhcp-protocol.h"
10 #include "dhcp-server-lease-internal.h"
11 #include "errno-util.h"
12 #include "extract-word.h"
16 #include "network-common.h"
17 #include "networkd-address.h"
18 #include "networkd-dhcp-server.h"
19 #include "networkd-dhcp-server-bus.h"
20 #include "networkd-dhcp-server-static-lease.h"
21 #include "networkd-link.h"
22 #include "networkd-manager.h"
23 #include "networkd-network.h"
24 #include "networkd-ntp.h"
25 #include "networkd-queue.h"
26 #include "networkd-route-util.h"
27 #include "path-util.h"
29 #include "socket-netlink.h"
30 #include "string-table.h"
31 #include "string-util.h"
34 static bool link_dhcp4_server_enabled(Link
*link
) {
37 if (link
->flags
& IFF_LOOPBACK
)
43 if (link
->iftype
== ARPHRD_CAN
)
46 return link
->network
->dhcp_server
;
49 int network_adjust_dhcp_server(Network
*network
, Set
**addresses
) {
55 if (!network
->dhcp_server
)
59 log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
61 network
->dhcp_server
= false;
65 assert(network
->dhcp_server_address_prefixlen
<= 32);
67 if (network
->dhcp_server_address_prefixlen
== 0) {
70 /* If the server address is not specified, then find suitable static address. */
72 ORDERED_HASHMAP_FOREACH(address
, network
->addresses_by_section
) {
73 assert(!section_is_invalid(address
->section
));
75 if (address
->family
!= AF_INET
)
78 if (in4_addr_is_localhost(&address
->in_addr
.in
))
81 if (in4_addr_is_link_local(&address
->in_addr
.in
))
84 if (in4_addr_is_set(&address
->in_addr_peer
.in
))
87 /* TODO: check if the prefix length is small enough for the pool. */
89 network
->dhcp_server_address
= address
;
90 address
->used_by_dhcp_server
= true;
93 if (!network
->dhcp_server_address
) {
94 log_warning("%s: DHCPServer= is enabled, but no suitable static address configured. "
95 "Disabling DHCP server.",
97 network
->dhcp_server
= false;
102 _cleanup_(address_unrefp
) Address
*a
= NULL
;
106 /* TODO: check if the prefix length is small enough for the pool. */
108 /* If an address is explicitly specified, then check if the corresponding [Address] section
109 * is configured, and add one if not. */
111 existing
= set_get(*addresses
,
114 .in_addr
.in
= network
->dhcp_server_address_in_addr
,
115 .prefixlen
= network
->dhcp_server_address_prefixlen
,
118 /* Corresponding [Address] section already exists. */
119 network
->dhcp_server_address
= existing
;
123 r
= ordered_hashmap_by_section_find_unused_line(network
->addresses_by_section
, network
->filename
, &line
);
125 return log_warning_errno(r
, "%s: Failed to find unused line number for DHCP server address: %m",
128 r
= address_new_static(network
, network
->filename
, line
, &a
);
130 return log_warning_errno(r
, "%s: Failed to add new static address object for DHCP server: %m",
134 a
->prefixlen
= network
->dhcp_server_address_prefixlen
;
135 a
->in_addr
.in
= network
->dhcp_server_address_in_addr
;
136 a
->requested_as_null
= !in4_addr_is_set(&network
->dhcp_server_address_in_addr
);
137 a
->used_by_dhcp_server
= true;
139 r
= address_section_verify(a
);
143 r
= set_ensure_put(addresses
, &address_hash_ops
, a
);
148 network
->dhcp_server_address
= TAKE_PTR(a
);
154 static DHCPServerPersistLeases
link_get_dhcp_server_persist_leases(Link
*link
) {
156 assert(link
->manager
);
157 assert(link
->network
);
159 if (in4_addr_is_set(&link
->network
->dhcp_server_relay_target
))
160 return DHCP_SERVER_PERSIST_LEASES_NO
; /* On relay mode. Nothing saved in the persistent storage. */
162 if (link
->network
->dhcp_server_persist_leases
>= 0)
163 return link
->network
->dhcp_server_persist_leases
;
165 return link
->manager
->dhcp_server_persist_leases
;
168 static int link_get_dhcp_server_lease_file(Link
*link
, int *ret_dir_fd
, char **ret_path
) {
170 assert(link
->ifname
);
174 /* This does not copy fd. Do not close fd stored in ret_dir_fd. */
176 switch (link_get_dhcp_server_persist_leases(link
)) {
177 case DHCP_SERVER_PERSIST_LEASES_NO
:
178 *ret_dir_fd
= -EBADF
;
182 case DHCP_SERVER_PERSIST_LEASES_YES
: {
183 if (link
->manager
->persistent_storage_fd
< 0)
184 return -EBUSY
; /* persistent storage is not ready. */
186 char *p
= path_join("dhcp-server-lease", link
->ifname
);
190 *ret_dir_fd
= link
->manager
->persistent_storage_fd
;
194 case DHCP_SERVER_PERSIST_LEASES_RUNTIME
: {
195 char *p
= path_join("/run/systemd/netif/dhcp-server-lease", link
->ifname
);
199 *ret_dir_fd
= AT_FDCWD
;
204 assert_not_reached();
208 int address_acquire_from_dhcp_server_leases_file(Link
*link
, const Address
*address
, union in_addr_union
*ret
) {
212 assert(link
->manager
);
216 /* If the DHCP server address is configured as a null address, reuse the server address of the
217 * previous instance. */
218 if (address
->family
!= AF_INET
)
221 if (!address
->used_by_dhcp_server
)
224 if (!link_dhcp4_server_enabled(link
))
227 _cleanup_free_
char *lease_file
= NULL
;
229 r
= link_get_dhcp_server_lease_file(link
, &dir_fd
, &lease_file
);
232 if (r
== 0) /* persistent leases is disabled */
237 r
= dhcp_server_leases_file_get_server_address(
245 return log_warning_errno(r
, "Failed to load lease file %s: %s",
247 r
== -ENXIO
? "expected JSON content not found" :
248 r
== -EINVAL
? "invalid JSON" :
251 if (prefixlen
!= address
->prefixlen
)
258 int link_start_dhcp4_server(Link
*link
) {
262 assert(link
->manager
);
264 if (!link
->dhcp_server
)
265 return 0; /* Not configured yet. */
267 if (!link_has_carrier(link
))
270 if (sd_dhcp_server_is_running(link
->dhcp_server
))
271 return 0; /* already started. */
273 /* TODO: Maybe, also check the system time is synced. If the system does not have RTC battery, then
274 * the realtime clock in not usable in the early boot stage, and all saved leases may be wrongly
275 * handled as expired and dropped. */
276 _cleanup_free_
char *lease_file
= NULL
;
278 r
= link_get_dhcp_server_lease_file(link
, &dir_fd
, &lease_file
);
280 return 0; /* persistent storage is not ready. */
284 r
= sd_dhcp_server_set_lease_file(link
->dhcp_server
, dir_fd
, lease_file
);
289 r
= sd_dhcp_server_start(link
->dhcp_server
);
293 log_link_debug(link
, "Offering DHCPv4 leases");
297 void manager_toggle_dhcp4_server_state(Manager
*manager
, bool start
) {
303 HASHMAP_FOREACH(link
, manager
->links_by_index
) {
304 if (!link
->dhcp_server
)
306 if (link_get_dhcp_server_persist_leases(link
) != DHCP_SERVER_PERSIST_LEASES_YES
)
309 /* Even if 'start' is true, first we need to stop the server. Otherwise, we cannot (re)set
310 * the lease file in link_start_dhcp4_server(). */
311 r
= sd_dhcp_server_stop(link
->dhcp_server
);
313 log_link_debug_errno(link
, r
, "Failed to stop DHCP server, ignoring: %m");
318 r
= link_start_dhcp4_server(link
);
320 log_link_debug_errno(link
, r
, "Failed to start DHCP server, ignoring: %m");
324 static int dhcp_server_find_uplink(Link
*link
, Link
**ret
) {
327 if (link
->network
->dhcp_server_uplink_name
)
328 return link_get_by_name(link
->manager
, link
->network
->dhcp_server_uplink_name
, ret
);
330 if (link
->network
->dhcp_server_uplink_index
> 0)
331 return link_get_by_index(link
->manager
, link
->network
->dhcp_server_uplink_index
, ret
);
333 if (link
->network
->dhcp_server_uplink_index
== UPLINK_INDEX_AUTO
) {
334 /* It is not necessary to propagate error in automatic selection. */
335 if (manager_find_uplink(link
->manager
, AF_INET
, link
, ret
) < 0)
344 static int link_push_uplink_to_dhcp_server(
346 sd_dhcp_lease_server_type_t what
,
349 _cleanup_free_
struct in_addr
*addresses
= NULL
;
350 bool use_dhcp_lease_data
= true;
351 size_t n_addresses
= 0;
357 assert(link
->network
);
359 log_link_debug(link
, "Copying %s from link", dhcp_lease_server_type_to_string(what
));
363 case SD_DHCP_LEASE_DNS
:
364 /* For DNS we have a special case. We the data configured explicitly locally along with the
365 * data from the DHCP lease. */
367 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
370 /* Only look for IPv4 addresses */
371 if (link
->network
->dns
[i
]->family
!= AF_INET
)
374 ia
= link
->network
->dns
[i
]->address
.in
;
376 /* Never propagate obviously borked data */
377 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
380 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
383 addresses
[n_addresses
++] = ia
;
386 use_dhcp_lease_data
= link_get_use_dns(link
, NETWORK_CONFIG_SOURCE_DHCP4
);
389 case SD_DHCP_LEASE_NTP
: {
390 /* For NTP things are similar, but for NTP hostnames can be configured too, which we cannot
391 * propagate via DHCP. Hence let's only propagate those which are IP addresses. */
393 STRV_FOREACH(i
, link
->network
->ntp
) {
394 union in_addr_union ia
;
396 if (in_addr_from_string(AF_INET
, *i
, &ia
) < 0)
399 /* Never propagate obviously borked data */
400 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
403 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
406 addresses
[n_addresses
++] = ia
.in
;
409 use_dhcp_lease_data
= link_get_use_ntp(link
, NETWORK_CONFIG_SOURCE_DHCP4
);
413 case SD_DHCP_LEASE_SIP
:
415 /* For SIP we don't allow explicit, local configuration, but there's control whether to use the data */
416 use_dhcp_lease_data
= link
->network
->dhcp_use_sip
;
419 case SD_DHCP_LEASE_POP3
:
420 case SD_DHCP_LEASE_SMTP
:
421 case SD_DHCP_LEASE_LPR
:
422 /* For the other server types we currently do not allow local configuration of server data,
423 * since there are typically no local consumers of the data. */
427 assert_not_reached();
430 if (use_dhcp_lease_data
&& link
->dhcp_lease
) {
431 const struct in_addr
*da
;
433 int n
= sd_dhcp_lease_get_servers(link
->dhcp_lease
, what
, &da
);
435 if (!GREEDY_REALLOC(addresses
, n_addresses
+ n
))
438 for (int j
= 0; j
< n
; j
++)
439 if (in4_addr_is_non_local(&da
[j
]))
440 addresses
[n_addresses
++] = da
[j
];
444 if (n_addresses
<= 0)
447 return sd_dhcp_server_set_servers(s
, what
, addresses
, n_addresses
);
450 static int dhcp4_server_parse_dns_server_string_and_warn(
452 struct in_addr
**addresses
,
453 size_t *n_addresses
) {
456 _cleanup_free_
char *word
= NULL
, *server_name
= NULL
;
457 union in_addr_union address
;
458 int family
, r
, ifindex
= 0;
460 r
= extract_first_word(&string
, &word
, NULL
, 0);
466 r
= in_addr_ifindex_name_from_string_auto(word
, &family
, &address
, &ifindex
, &server_name
);
468 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring: %m", word
);
472 /* Only look for IPv4 addresses */
473 if (family
!= AF_INET
)
476 /* Never propagate obviously borked data */
477 if (in4_addr_is_null(&address
.in
) || in4_addr_is_localhost(&address
.in
))
480 if (!GREEDY_REALLOC(*addresses
, *n_addresses
+ 1))
483 (*addresses
)[(*n_addresses
)++] = address
.in
;
489 static int dhcp4_server_set_dns_from_resolve_conf(Link
*link
) {
490 _cleanup_free_
struct in_addr
*addresses
= NULL
;
491 _cleanup_fclose_
FILE *f
= NULL
;
492 size_t n_addresses
= 0;
495 f
= fopen(PRIVATE_UPLINK_RESOLV_CONF
, "re");
500 return log_warning_errno(errno
, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF
": %m");
504 _cleanup_free_
char *line
= NULL
;
507 r
= read_stripped_line(f
, LONG_LINE_MAX
, &line
);
509 return log_error_errno(r
, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF
": %m");
513 if (IN_SET(*line
, '#', ';', 0))
516 a
= first_word(line
, "nameserver");
520 r
= dhcp4_server_parse_dns_server_string_and_warn(a
, &addresses
, &n_addresses
);
522 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring.", a
);
525 if (n_addresses
<= 0)
528 return sd_dhcp_server_set_dns(link
->dhcp_server
, addresses
, n_addresses
);
531 static int dhcp4_server_configure(Link
*link
) {
532 bool acquired_uplink
= false;
534 DHCPStaticLease
*static_lease
;
537 bool bind_to_interface
;
541 assert(link
->network
);
542 assert(link
->network
->dhcp_server_address
);
544 log_link_debug(link
, "Configuring DHCP Server.");
546 if (link
->dhcp_server
)
549 r
= sd_dhcp_server_new(&link
->dhcp_server
, link
->ifindex
);
553 r
= sd_dhcp_server_attach_event(link
->dhcp_server
, link
->manager
->event
, 0);
557 r
= sd_dhcp_server_set_callback(link
->dhcp_server
, dhcp_server_callback
, link
);
559 return log_link_warning_errno(link
, r
, "Failed to set callback for DHCPv4 server instance: %m");
561 r
= address_get(link
, link
->network
->dhcp_server_address
, &address
);
563 return log_link_error_errno(link
, r
, "Failed to find suitable address for DHCPv4 server instance: %m");
565 /* use the server address' subnet as the pool */
566 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
567 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
569 return log_link_error_errno(link
, r
, "Failed to configure address pool for DHCPv4 server instance: %m");
571 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
572 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
, link
->network
->dhcp_server_max_lease_time_usec
);
574 return log_link_error_errno(link
, r
, "Failed to set maximum lease time for DHCPv4 server instance: %m");
577 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
578 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
, link
->network
->dhcp_server_default_lease_time_usec
);
580 return log_link_error_errno(link
, r
, "Failed to set default lease time for DHCPv4 server instance: %m");
583 r
= sd_dhcp_server_set_ipv6_only_preferred_usec(link
->dhcp_server
, link
->network
->dhcp_server_ipv6_only_preferred_usec
);
585 return log_link_error_errno(link
, r
, "Failed to set IPv6 only preferred time for DHCPv4 server instance: %m");
587 r
= sd_dhcp_server_set_boot_server_address(link
->dhcp_server
, &link
->network
->dhcp_server_boot_server_address
);
589 return log_link_warning_errno(link
, r
, "Failed to set boot server address for DHCPv4 server instance: %m");
591 r
= sd_dhcp_server_set_boot_server_name(link
->dhcp_server
, link
->network
->dhcp_server_boot_server_name
);
593 return log_link_warning_errno(link
, r
, "Failed to set boot server name for DHCPv4 server instance: %m");
595 r
= sd_dhcp_server_set_boot_filename(link
->dhcp_server
, link
->network
->dhcp_server_boot_filename
);
597 return log_link_warning_errno(link
, r
, "Failed to set boot filename for DHCPv4 server instance: %m");
599 r
= sd_dhcp_server_set_rapid_commit(link
->dhcp_server
, link
->network
->dhcp_server_rapid_commit
);
601 return log_link_warning_errno(link
, r
, "Failed to %s Rapid Commit support for DHCPv4 server instance: %m",
602 enable_disable(link
->network
->dhcp_server_rapid_commit
));
604 for (sd_dhcp_lease_server_type_t type
= 0; type
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; type
++) {
606 if (!link
->network
->dhcp_server_emit
[type
].emit
)
609 if (link
->network
->dhcp_server_emit
[type
].n_addresses
> 0)
610 /* Explicitly specified servers to emit */
611 r
= sd_dhcp_server_set_servers(
614 link
->network
->dhcp_server_emit
[type
].addresses
,
615 link
->network
->dhcp_server_emit
[type
].n_addresses
);
617 /* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */
618 if (!acquired_uplink
) {
619 (void) dhcp_server_find_uplink(link
, &uplink
);
620 acquired_uplink
= true;
623 if (uplink
&& uplink
->network
)
624 r
= link_push_uplink_to_dhcp_server(uplink
, type
, link
->dhcp_server
);
625 else if (type
== SD_DHCP_LEASE_DNS
)
626 r
= dhcp4_server_set_dns_from_resolve_conf(link
);
629 "Not emitting %s on link, couldn't find suitable uplink.",
630 dhcp_lease_server_type_to_string(type
));
636 log_link_warning_errno(link
, r
,
637 "Failed to set %s for DHCP server, ignoring: %m",
638 dhcp_lease_server_type_to_string(type
));
641 if (link
->network
->dhcp_server_emit_router
) {
642 r
= sd_dhcp_server_set_router(link
->dhcp_server
, &link
->network
->dhcp_server_router
);
644 return log_link_error_errno(link
, r
, "Failed to set router address for DHCP server: %m");
647 r
= sd_dhcp_server_set_relay_target(link
->dhcp_server
, &link
->network
->dhcp_server_relay_target
);
649 return log_link_error_errno(link
, r
, "Failed to set relay target for DHCP server: %m");
651 bind_to_interface
= sd_dhcp_server_is_in_relay_mode(link
->dhcp_server
) ? false : link
->network
->dhcp_server_bind_to_interface
;
652 r
= sd_dhcp_server_set_bind_to_interface(link
->dhcp_server
, bind_to_interface
);
654 return log_link_error_errno(link
, r
, "Failed to set interface binding for DHCP server: %m");
656 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
);
658 return log_link_error_errno(link
, r
, "Failed to set agent circuit/remote id for DHCP server: %m");
660 if (link
->network
->dhcp_server_emit_timezone
) {
661 _cleanup_free_
char *buffer
= NULL
;
662 const char *tz
= NULL
;
664 if (link
->network
->dhcp_server_timezone
)
665 tz
= link
->network
->dhcp_server_timezone
;
667 r
= get_timezone(&buffer
);
669 log_link_warning_errno(link
, r
, "Failed to determine timezone, not sending timezone: %m");
675 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
677 return log_link_error_errno(link
, r
, "Failed to set timezone for DHCP server: %m");
681 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
) {
682 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
686 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
689 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_vendor_options
) {
690 r
= sd_dhcp_server_add_vendor_option(link
->dhcp_server
, p
);
694 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
697 HASHMAP_FOREACH(static_lease
, link
->network
->dhcp_static_leases_by_section
) {
698 r
= sd_dhcp_server_set_static_lease(link
->dhcp_server
, &static_lease
->address
, static_lease
->client_id
, static_lease
->client_id_size
);
700 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 static lease for DHCP server: %m");
703 r
= link_start_dhcp4_server(link
);
705 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
710 static bool dhcp_server_is_ready_to_configure(Link
*link
) {
715 assert(link
->network
);
716 assert(link
->network
->dhcp_server_address
);
718 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
721 if (!link_has_carrier(link
))
724 if (!link
->static_addresses_configured
)
727 if (address_get(link
, link
->network
->dhcp_server_address
, &a
) < 0)
730 if (!address_is_ready(a
))
733 if (dhcp_server_find_uplink(link
, &uplink
) < 0)
736 if (uplink
&& !uplink
->network
)
742 static int dhcp_server_process_request(Request
*req
, Link
*link
, void *userdata
) {
747 if (!dhcp_server_is_ready_to_configure(link
))
750 r
= dhcp4_server_configure(link
);
752 return log_link_warning_errno(link
, r
, "Failed to configure DHCP server: %m");
757 int link_request_dhcp_server(Link
*link
) {
762 if (!link_dhcp4_server_enabled(link
))
765 if (link
->dhcp_server
)
768 log_link_debug(link
, "Requesting DHCP server.");
769 r
= link_queue_request(link
, REQUEST_TYPE_DHCP_SERVER
, dhcp_server_process_request
, NULL
);
771 return log_link_warning_errno(link
, r
, "Failed to request configuration of DHCP server: %m");
776 int config_parse_dhcp_server_relay_agent_suboption(
778 const char *filename
,
781 unsigned section_line
,
788 char **suboption_value
= data
;
795 if (isempty(rvalue
)) {
796 *suboption_value
= mfree(*suboption_value
);
800 p
= startswith(rvalue
, "string:");
802 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
803 "Failed to parse %s=%s'. Invalid format, ignoring.", lvalue
, rvalue
);
806 return free_and_strdup(suboption_value
, empty_to_null(p
));
809 int config_parse_dhcp_server_emit(
811 const char *filename
,
814 unsigned section_line
,
821 NetworkDHCPServerEmitAddress
*emit
= ASSERT_PTR(data
);
825 if (isempty(rvalue
)) {
826 emit
->addresses
= mfree(emit
->addresses
);
827 emit
->n_addresses
= 0;
831 for (const char *p
= rvalue
;;) {
832 _cleanup_free_
char *w
= NULL
;
833 union in_addr_union a
;
836 r
= extract_first_word(&p
, &w
, NULL
, 0);
840 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
841 "Failed to extract word, ignoring: %s", rvalue
);
847 if (streq(w
, "_server_address"))
848 a
= IN_ADDR_NULL
; /* null address will be converted to the server address. */
850 r
= in_addr_from_string(AF_INET
, w
, &a
);
852 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
853 "Failed to parse %s= address '%s', ignoring: %m", lvalue
, w
);
857 if (in4_addr_is_null(&a
.in
)) {
858 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
859 "Found a null address in %s=, ignoring.", lvalue
);
864 if (!GREEDY_REALLOC(emit
->addresses
, emit
->n_addresses
+ 1))
867 emit
->addresses
[emit
->n_addresses
++] = a
.in
;
871 int config_parse_dhcp_server_address(
873 const char *filename
,
876 unsigned section_line
,
883 Network
*network
= ASSERT_PTR(userdata
);
884 union in_addr_union a
;
885 unsigned char prefixlen
;
892 if (isempty(rvalue
)) {
893 network
->dhcp_server_address_in_addr
= (struct in_addr
) {};
894 network
->dhcp_server_address_prefixlen
= 0;
898 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &a
, &prefixlen
);
900 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
901 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
904 if (in4_addr_is_localhost(&a
.in
) || in4_addr_is_link_local(&a
.in
)) {
905 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
906 "DHCP server address cannot be a localhost or link-local address, "
907 "ignoring assignment: %s", rvalue
);
911 network
->dhcp_server_address_in_addr
= a
.in
;
912 network
->dhcp_server_address_prefixlen
= prefixlen
;
916 int config_parse_dhcp_server_ipv6_only_preferred(
918 const char *filename
,
921 unsigned section_line
,
928 usec_t t
, *usec
= ASSERT_PTR(data
);
936 if (isempty(rvalue
)) {
941 r
= parse_sec(rvalue
, &t
);
943 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
944 "Failed to parse [%s] %s=, ignoring assignment: %s", section
, lvalue
, rvalue
);
948 if (t
< MIN_V6ONLY_WAIT_USEC
&& !network_test_mode_enabled()) {
949 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
950 "Invalid [%s] %s=, ignoring assignment: %s", section
, lvalue
, rvalue
);
958 static const char* const dhcp_server_persist_leases_table
[_DHCP_SERVER_PERSIST_LEASES_MAX
] = {
959 [DHCP_SERVER_PERSIST_LEASES_NO
] = "no",
960 [DHCP_SERVER_PERSIST_LEASES_YES
] = "yes",
961 [DHCP_SERVER_PERSIST_LEASES_RUNTIME
] = "runtime",
964 DEFINE_PRIVATE_STRING_TABLE_LOOKUP_FROM_STRING_WITH_BOOLEAN(
965 dhcp_server_persist_leases
,
966 DHCPServerPersistLeases
,
967 DHCP_SERVER_PERSIST_LEASES_YES
);
969 DEFINE_CONFIG_PARSE_ENUM(
970 config_parse_dhcp_server_persist_leases
,
971 dhcp_server_persist_leases
,
972 DHCPServerPersistLeases
);