1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
3 #include <netinet/in.h>
4 #include <linux/if_arp.h>
7 #include "sd-dhcp-server.h"
11 #include "networkd-address.h"
12 #include "networkd-dhcp-server-bus.h"
13 #include "networkd-dhcp-server-static-lease.h"
14 #include "networkd-dhcp-server.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "networkd-network.h"
18 #include "networkd-queue.h"
19 #include "networkd-route-util.h"
20 #include "parse-util.h"
21 #include "socket-netlink.h"
22 #include "string-table.h"
23 #include "string-util.h"
26 static bool link_dhcp4_server_enabled(Link
*link
) {
29 if (link
->flags
& IFF_LOOPBACK
)
35 if (link
->iftype
== ARPHRD_CAN
)
38 return link
->network
->dhcp_server
;
41 int network_adjust_dhcp_server(Network
*network
, Set
**addresses
) {
47 if (!network
->dhcp_server
)
51 log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
53 network
->dhcp_server
= false;
57 assert(network
->dhcp_server_address_prefixlen
<= 32);
59 if (network
->dhcp_server_address_prefixlen
== 0) {
62 /* If the server address is not specified, then find suitable static address. */
64 ORDERED_HASHMAP_FOREACH(address
, network
->addresses_by_section
) {
65 assert(!section_is_invalid(address
->section
));
67 if (address
->family
!= AF_INET
)
70 if (in4_addr_is_localhost(&address
->in_addr
.in
))
73 if (in4_addr_is_link_local(&address
->in_addr
.in
))
76 if (in4_addr_is_set(&address
->in_addr_peer
.in
))
79 /* TODO: check if the prefix length is small enough for the pool. */
81 network
->dhcp_server_address
= address
;
84 if (!network
->dhcp_server_address
) {
85 log_warning("%s: DHCPServer= is enabled, but no suitable static address configured. "
86 "Disabling DHCP server.",
88 network
->dhcp_server
= false;
93 _cleanup_(address_freep
) Address
*a
= NULL
;
97 /* TODO: check if the prefix length is small enough for the pool. */
99 /* If an address is explicitly specified, then check if the corresponding [Address] section
100 * is configured, and add one if not. */
102 existing
= set_get(*addresses
,
105 .in_addr
.in
= network
->dhcp_server_address_in_addr
,
106 .prefixlen
= network
->dhcp_server_address_prefixlen
,
109 /* Corresponding [Address] section already exists. */
110 network
->dhcp_server_address
= existing
;
114 r
= ordered_hashmap_by_section_find_unused_line(network
->addresses_by_section
, network
->filename
, &line
);
116 return log_warning_errno(r
, "%s: Failed to find unused line number for DHCP server address: %m",
119 r
= address_new_static(network
, network
->filename
, line
, &a
);
121 return log_warning_errno(r
, "%s: Failed to add new static address object for DHCP server: %m",
125 a
->prefixlen
= network
->dhcp_server_address_prefixlen
;
126 a
->in_addr
.in
= network
->dhcp_server_address_in_addr
;
127 a
->requested_as_null
= !in4_addr_is_set(&network
->dhcp_server_address_in_addr
);
129 r
= address_section_verify(a
);
133 r
= set_ensure_put(addresses
, &address_hash_ops
, a
);
138 network
->dhcp_server_address
= TAKE_PTR(a
);
144 static int dhcp_server_find_uplink(Link
*link
, Link
**ret
) {
147 if (link
->network
->dhcp_server_uplink_name
)
148 return link_get_by_name(link
->manager
, link
->network
->dhcp_server_uplink_name
, ret
);
150 if (link
->network
->dhcp_server_uplink_index
> 0)
151 return link_get_by_index(link
->manager
, link
->network
->dhcp_server_uplink_index
, ret
);
153 if (link
->network
->dhcp_server_uplink_index
== UPLINK_INDEX_AUTO
) {
154 /* It is not necessary to propagate error in automatic selection. */
155 if (manager_find_uplink(link
->manager
, AF_INET
, link
, ret
) < 0)
164 static int link_push_uplink_to_dhcp_server(
166 sd_dhcp_lease_server_type_t what
,
169 _cleanup_free_
struct in_addr
*addresses
= NULL
;
170 bool use_dhcp_lease_data
= true;
171 size_t n_addresses
= 0;
177 assert(link
->network
);
179 log_link_debug(link
, "Copying %s from link", dhcp_lease_server_type_to_string(what
));
183 case SD_DHCP_LEASE_DNS
:
184 /* For DNS we have a special case. We the data configured explicitly locally along with the
185 * data from the DHCP lease. */
187 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
190 /* Only look for IPv4 addresses */
191 if (link
->network
->dns
[i
]->family
!= AF_INET
)
194 ia
= link
->network
->dns
[i
]->address
.in
;
196 /* Never propagate obviously borked data */
197 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
200 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
203 addresses
[n_addresses
++] = ia
;
206 use_dhcp_lease_data
= link
->network
->dhcp_use_dns
;
209 case SD_DHCP_LEASE_NTP
: {
210 /* For NTP things are similar, but for NTP hostnames can be configured too, which we cannot
211 * propagate via DHCP. Hence let's only propagate those which are IP addresses. */
213 STRV_FOREACH(i
, link
->network
->ntp
) {
214 union in_addr_union ia
;
216 if (in_addr_from_string(AF_INET
, *i
, &ia
) < 0)
219 /* Never propagate obviously borked data */
220 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
223 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
226 addresses
[n_addresses
++] = ia
.in
;
229 use_dhcp_lease_data
= link
->network
->dhcp_use_ntp
;
233 case SD_DHCP_LEASE_SIP
:
235 /* For SIP we don't allow explicit, local configuration, but there's control whether to use the data */
236 use_dhcp_lease_data
= link
->network
->dhcp_use_sip
;
239 case SD_DHCP_LEASE_POP3
:
240 case SD_DHCP_LEASE_SMTP
:
241 case SD_DHCP_LEASE_LPR
:
242 /* For the other server types we currently do not allow local configuration of server data,
243 * since there are typically no local consumers of the data. */
247 assert_not_reached();
250 if (use_dhcp_lease_data
&& link
->dhcp_lease
) {
251 const struct in_addr
*da
;
253 int n
= sd_dhcp_lease_get_servers(link
->dhcp_lease
, what
, &da
);
255 if (!GREEDY_REALLOC(addresses
, n_addresses
+ n
))
258 for (int j
= 0; j
< n
; j
++)
259 if (in4_addr_is_non_local(&da
[j
]))
260 addresses
[n_addresses
++] = da
[j
];
264 if (n_addresses
<= 0)
267 return sd_dhcp_server_set_servers(s
, what
, addresses
, n_addresses
);
270 static int dhcp4_server_parse_dns_server_string_and_warn(
272 struct in_addr
**addresses
,
273 size_t *n_addresses
) {
276 _cleanup_free_
char *word
= NULL
, *server_name
= NULL
;
277 union in_addr_union address
;
278 int family
, r
, ifindex
= 0;
280 r
= extract_first_word(&string
, &word
, NULL
, 0);
286 r
= in_addr_ifindex_name_from_string_auto(word
, &family
, &address
, &ifindex
, &server_name
);
288 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring: %m", word
);
292 /* Only look for IPv4 addresses */
293 if (family
!= AF_INET
)
296 /* Never propagate obviously borked data */
297 if (in4_addr_is_null(&address
.in
) || in4_addr_is_localhost(&address
.in
))
300 if (!GREEDY_REALLOC(*addresses
, *n_addresses
+ 1))
303 (*addresses
)[(*n_addresses
)++] = address
.in
;
309 static int dhcp4_server_set_dns_from_resolve_conf(Link
*link
) {
310 _cleanup_free_
struct in_addr
*addresses
= NULL
;
311 _cleanup_fclose_
FILE *f
= NULL
;
312 size_t n_addresses
= 0;
315 f
= fopen(PRIVATE_UPLINK_RESOLV_CONF
, "re");
320 return log_warning_errno(errno
, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF
": %m");
324 _cleanup_free_
char *line
= NULL
;
328 r
= read_line(f
, LONG_LINE_MAX
, &line
);
330 return log_error_errno(r
, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF
": %m");
335 if (IN_SET(*l
, '#', ';', 0))
338 a
= first_word(l
, "nameserver");
342 r
= dhcp4_server_parse_dns_server_string_and_warn(a
, &addresses
, &n_addresses
);
344 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring.", a
);
347 if (n_addresses
<= 0)
350 return sd_dhcp_server_set_dns(link
->dhcp_server
, addresses
, n_addresses
);
353 static int dhcp4_server_configure(Link
*link
) {
354 bool acquired_uplink
= false;
356 DHCPStaticLease
*static_lease
;
359 bool bind_to_interface
;
363 assert(link
->network
);
364 assert(link
->network
->dhcp_server_address
);
366 log_link_debug(link
, "Configuring DHCP Server.");
368 if (link
->dhcp_server
)
371 r
= sd_dhcp_server_new(&link
->dhcp_server
, link
->ifindex
);
375 r
= sd_dhcp_server_attach_event(link
->dhcp_server
, link
->manager
->event
, 0);
379 r
= sd_dhcp_server_set_callback(link
->dhcp_server
, dhcp_server_callback
, link
);
381 return log_link_warning_errno(link
, r
, "Failed to set callback for DHCPv4 server instance: %m");
383 r
= address_get(link
, link
->network
->dhcp_server_address
, &address
);
385 return log_link_error_errno(link
, r
, "Failed to find suitable address for DHCPv4 server instance: %m");
387 /* use the server address' subnet as the pool */
388 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
389 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
391 return log_link_error_errno(link
, r
, "Failed to configure address pool for DHCPv4 server instance: %m");
393 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
394 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
, link
->network
->dhcp_server_max_lease_time_usec
);
396 return log_link_error_errno(link
, r
, "Failed to set maximum lease time for DHCPv4 server instance: %m");
399 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
400 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
, link
->network
->dhcp_server_default_lease_time_usec
);
402 return log_link_error_errno(link
, r
, "Failed to set default lease time for DHCPv4 server instance: %m");
405 r
= sd_dhcp_server_set_boot_server_address(link
->dhcp_server
, &link
->network
->dhcp_server_boot_server_address
);
407 return log_link_warning_errno(link
, r
, "Failed to set boot server address for DHCPv4 server instance: %m");
409 r
= sd_dhcp_server_set_boot_server_name(link
->dhcp_server
, link
->network
->dhcp_server_boot_server_name
);
411 return log_link_warning_errno(link
, r
, "Failed to set boot server name for DHCPv4 server instance: %m");
413 r
= sd_dhcp_server_set_boot_filename(link
->dhcp_server
, link
->network
->dhcp_server_boot_filename
);
415 return log_link_warning_errno(link
, r
, "Failed to set boot filename for DHCPv4 server instance: %m");
417 for (sd_dhcp_lease_server_type_t type
= 0; type
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; type
++) {
419 if (!link
->network
->dhcp_server_emit
[type
].emit
)
422 if (link
->network
->dhcp_server_emit
[type
].n_addresses
> 0)
423 /* Explicitly specified servers to emit */
424 r
= sd_dhcp_server_set_servers(
427 link
->network
->dhcp_server_emit
[type
].addresses
,
428 link
->network
->dhcp_server_emit
[type
].n_addresses
);
430 /* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */
431 if (!acquired_uplink
) {
432 (void) dhcp_server_find_uplink(link
, &uplink
);
433 acquired_uplink
= true;
436 if (uplink
&& uplink
->network
)
437 r
= link_push_uplink_to_dhcp_server(uplink
, type
, link
->dhcp_server
);
438 else if (type
== SD_DHCP_LEASE_DNS
)
439 r
= dhcp4_server_set_dns_from_resolve_conf(link
);
442 "Not emitting %s on link, couldn't find suitable uplink.",
443 dhcp_lease_server_type_to_string(type
));
449 log_link_warning_errno(link
, r
,
450 "Failed to set %s for DHCP server, ignoring: %m",
451 dhcp_lease_server_type_to_string(type
));
454 if (link
->network
->dhcp_server_emit_router
) {
455 r
= sd_dhcp_server_set_router(link
->dhcp_server
, &link
->network
->dhcp_server_router
);
457 return log_link_error_errno(link
, r
, "Failed to set router address for DHCP server: %m");
460 r
= sd_dhcp_server_set_relay_target(link
->dhcp_server
, &link
->network
->dhcp_server_relay_target
);
462 return log_link_error_errno(link
, r
, "Failed to set relay target for DHCP server: %m");
464 bind_to_interface
= sd_dhcp_server_is_in_relay_mode(link
->dhcp_server
) ? false : link
->network
->dhcp_server_bind_to_interface
;
465 r
= sd_dhcp_server_set_bind_to_interface(link
->dhcp_server
, bind_to_interface
);
467 return log_link_error_errno(link
, r
, "Failed to set interface binding for DHCP server: %m");
469 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
);
471 return log_link_error_errno(link
, r
, "Failed to set agent circuit/remote id for DHCP server: %m");
473 if (link
->network
->dhcp_server_emit_timezone
) {
474 _cleanup_free_
char *buffer
= NULL
;
475 const char *tz
= NULL
;
477 if (link
->network
->dhcp_server_timezone
)
478 tz
= link
->network
->dhcp_server_timezone
;
480 r
= get_timezone(&buffer
);
482 log_link_warning_errno(link
, r
, "Failed to determine timezone, not sending timezone: %m");
488 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
490 return log_link_error_errno(link
, r
, "Failed to set timezone for DHCP server: %m");
494 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
) {
495 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
499 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
502 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_vendor_options
) {
503 r
= sd_dhcp_server_add_vendor_option(link
->dhcp_server
, p
);
507 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
510 HASHMAP_FOREACH(static_lease
, link
->network
->dhcp_static_leases_by_section
) {
511 r
= sd_dhcp_server_set_static_lease(link
->dhcp_server
, &static_lease
->address
, static_lease
->client_id
, static_lease
->client_id_size
);
513 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 static lease for DHCP server: %m");
516 r
= sd_dhcp_server_start(link
->dhcp_server
);
518 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
520 log_link_debug(link
, "Offering DHCPv4 leases");
524 static bool dhcp_server_is_ready_to_configure(Link
*link
) {
529 assert(link
->network
);
530 assert(link
->network
->dhcp_server_address
);
532 if (!link_is_ready_to_configure(link
, /* allow_unmanaged = */ false))
535 if (!link_has_carrier(link
))
538 if (!link
->static_addresses_configured
)
541 if (address_get(link
, link
->network
->dhcp_server_address
, &a
) < 0)
544 if (!address_is_ready(a
))
547 if (dhcp_server_find_uplink(link
, &uplink
) < 0)
550 if (uplink
&& !uplink
->network
)
556 static int dhcp_server_process_request(Request
*req
, Link
*link
, void *userdata
) {
561 if (!dhcp_server_is_ready_to_configure(link
))
564 r
= dhcp4_server_configure(link
);
566 return log_link_warning_errno(link
, r
, "Failed to configure DHCP server: %m");
571 int link_request_dhcp_server(Link
*link
) {
576 if (!link_dhcp4_server_enabled(link
))
579 if (link
->dhcp_server
)
582 log_link_debug(link
, "Requesting DHCP server.");
583 r
= link_queue_request(link
, REQUEST_TYPE_DHCP_SERVER
, dhcp_server_process_request
, NULL
);
585 return log_link_warning_errno(link
, r
, "Failed to request configuration of DHCP server: %m");
590 int config_parse_dhcp_server_relay_agent_suboption(
592 const char *filename
,
595 unsigned section_line
,
602 char **suboption_value
= data
;
609 if (isempty(rvalue
)) {
610 *suboption_value
= mfree(*suboption_value
);
614 p
= startswith(rvalue
, "string:");
616 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
617 "Failed to parse %s=%s'. Invalid format, ignoring.", lvalue
, rvalue
);
620 return free_and_strdup(suboption_value
, empty_to_null(p
));
623 int config_parse_dhcp_server_emit(
625 const char *filename
,
628 unsigned section_line
,
635 NetworkDHCPServerEmitAddress
*emit
= ASSERT_PTR(data
);
639 if (isempty(rvalue
)) {
640 emit
->addresses
= mfree(emit
->addresses
);
641 emit
->n_addresses
= 0;
645 for (const char *p
= rvalue
;;) {
646 _cleanup_free_
char *w
= NULL
;
647 union in_addr_union a
;
650 r
= extract_first_word(&p
, &w
, NULL
, 0);
654 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
655 "Failed to extract word, ignoring: %s", rvalue
);
661 if (streq(w
, "_server_address"))
662 a
= IN_ADDR_NULL
; /* null address will be converted to the server address. */
664 r
= in_addr_from_string(AF_INET
, w
, &a
);
666 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
667 "Failed to parse %s= address '%s', ignoring: %m", lvalue
, w
);
671 if (in4_addr_is_null(&a
.in
)) {
672 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
673 "Found a null address in %s=, ignoring.", lvalue
);
678 if (!GREEDY_REALLOC(emit
->addresses
, emit
->n_addresses
+ 1))
681 emit
->addresses
[emit
->n_addresses
++] = a
.in
;
685 int config_parse_dhcp_server_address(
687 const char *filename
,
690 unsigned section_line
,
697 Network
*network
= ASSERT_PTR(userdata
);
698 union in_addr_union a
;
699 unsigned char prefixlen
;
706 if (isempty(rvalue
)) {
707 network
->dhcp_server_address_in_addr
= (struct in_addr
) {};
708 network
->dhcp_server_address_prefixlen
= 0;
712 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &a
, &prefixlen
);
714 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
715 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
718 if (in4_addr_is_localhost(&a
.in
) || in4_addr_is_link_local(&a
.in
)) {
719 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
720 "DHCP server address cannot be a localhost or link-local address, "
721 "ignoring assignment: %s", rvalue
);
725 network
->dhcp_server_address_in_addr
= a
.in
;
726 network
->dhcp_server_address_prefixlen
= prefixlen
;