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 "parse-util.h"
20 #include "socket-netlink.h"
21 #include "string-table.h"
22 #include "string-util.h"
25 static bool link_dhcp4_server_enabled(Link
*link
) {
28 if (link
->flags
& IFF_LOOPBACK
)
34 if (link
->iftype
== ARPHRD_CAN
)
37 return link
->network
->dhcp_server
;
40 void network_adjust_dhcp_server(Network
*network
) {
43 if (!network
->dhcp_server
)
47 log_warning("%s: DHCPServer= is enabled for bond slave. Disabling DHCP server.",
49 network
->dhcp_server
= false;
53 if (!in4_addr_is_set(&network
->dhcp_server_address
)) {
57 ORDERED_HASHMAP_FOREACH(address
, network
->addresses_by_section
) {
58 if (section_is_invalid(address
->section
))
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
)) {
68 log_warning("%s: DHCPServer= is enabled, but no static address configured. "
69 "Disabling DHCP server.",
71 network
->dhcp_server
= false;
77 static int link_find_dhcp_server_address(Link
*link
, Address
**ret
) {
81 assert(link
->network
);
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
);
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
)) {
100 static int dhcp_server_find_uplink(Link
*link
, Link
**ret
) {
103 if (link
->network
->dhcp_server_uplink_name
)
104 return link_get_by_name(link
->manager
, link
->network
->dhcp_server_uplink_name
, ret
);
106 if (link
->network
->dhcp_server_uplink_index
> 0)
107 return link_get_by_index(link
->manager
, link
->network
->dhcp_server_uplink_index
, ret
);
109 if (link
->network
->dhcp_server_uplink_index
== UPLINK_INDEX_AUTO
) {
110 /* It is not necessary to propagate error in automatic selection. */
111 if (manager_find_uplink(link
->manager
, AF_INET
, link
, ret
) < 0)
120 static int link_push_uplink_to_dhcp_server(
122 sd_dhcp_lease_server_type_t what
,
125 _cleanup_free_
struct in_addr
*addresses
= NULL
;
126 bool use_dhcp_lease_data
= true;
127 size_t n_addresses
= 0;
133 assert(link
->network
);
135 log_link_debug(link
, "Copying %s from link", dhcp_lease_server_type_to_string(what
));
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. */
143 for (unsigned i
= 0; i
< link
->network
->n_dns
; i
++) {
146 /* Only look for IPv4 addresses */
147 if (link
->network
->dns
[i
]->family
!= AF_INET
)
150 ia
= link
->network
->dns
[i
]->address
.in
;
152 /* Never propagate obviously borked data */
153 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
156 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
159 addresses
[n_addresses
++] = ia
;
162 use_dhcp_lease_data
= link
->network
->dhcp_use_dns
;
165 case SD_DHCP_LEASE_NTP
: {
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. */
171 STRV_FOREACH(i
, link
->network
->ntp
) {
172 union in_addr_union ia
;
174 if (in_addr_from_string(AF_INET
, *i
, &ia
) < 0)
177 /* Never propagate obviously borked data */
178 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
181 if (!GREEDY_REALLOC(addresses
, n_addresses
+ 1))
184 addresses
[n_addresses
++] = ia
.in
;
187 use_dhcp_lease_data
= link
->network
->dhcp_use_ntp
;
191 case SD_DHCP_LEASE_SIP
:
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
;
197 case SD_DHCP_LEASE_POP3
:
198 case SD_DHCP_LEASE_SMTP
:
199 case SD_DHCP_LEASE_LPR
:
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. */
205 assert_not_reached();
208 if (use_dhcp_lease_data
&& link
->dhcp_lease
) {
209 const struct in_addr
*da
;
211 int n
= sd_dhcp_lease_get_servers(link
->dhcp_lease
, what
, &da
);
213 if (!GREEDY_REALLOC(addresses
, n_addresses
+ n
))
216 for (int j
= 0; j
< n
; j
++)
217 if (in4_addr_is_non_local(&da
[j
]))
218 addresses
[n_addresses
++] = da
[j
];
222 if (n_addresses
<= 0)
225 return sd_dhcp_server_set_servers(s
, what
, addresses
, n_addresses
);
228 static int dhcp4_server_parse_dns_server_string_and_warn(
230 struct in_addr
**addresses
,
231 size_t *n_addresses
) {
234 _cleanup_free_
char *word
= NULL
, *server_name
= NULL
;
235 union in_addr_union address
;
236 int family
, r
, ifindex
= 0;
238 r
= extract_first_word(&string
, &word
, NULL
, 0);
244 r
= in_addr_ifindex_name_from_string_auto(word
, &family
, &address
, &ifindex
, &server_name
);
246 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring: %m", word
);
250 /* Only look for IPv4 addresses */
251 if (family
!= AF_INET
)
254 /* Never propagate obviously borked data */
255 if (in4_addr_is_null(&address
.in
) || in4_addr_is_localhost(&address
.in
))
258 if (!GREEDY_REALLOC(*addresses
, *n_addresses
+ 1))
261 (*addresses
)[(*n_addresses
)++] = address
.in
;
267 static int dhcp4_server_set_dns_from_resolve_conf(Link
*link
) {
268 _cleanup_free_
struct in_addr
*addresses
= NULL
;
269 _cleanup_fclose_
FILE *f
= NULL
;
270 size_t n_addresses
= 0;
273 f
= fopen(PRIVATE_UPLINK_RESOLV_CONF
, "re");
278 return log_warning_errno(errno
, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF
": %m");
282 _cleanup_free_
char *line
= NULL
;
286 r
= read_line(f
, LONG_LINE_MAX
, &line
);
288 return log_error_errno(r
, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF
": %m");
295 if (IN_SET(*l
, '#', ';', 0))
298 a
= first_word(l
, "nameserver");
302 r
= dhcp4_server_parse_dns_server_string_and_warn(a
, &addresses
, &n_addresses
);
304 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring.", a
);
307 if (n_addresses
<= 0)
310 return sd_dhcp_server_set_dns(link
->dhcp_server
, addresses
, n_addresses
);
313 static int dhcp4_server_configure(Link
*link
) {
314 bool acquired_uplink
= false;
316 DHCPStaticLease
*static_lease
;
319 bool bind_to_interface
;
324 log_link_debug(link
, "Configuring DHCP Server.");
326 if (link
->dhcp_server
)
329 r
= sd_dhcp_server_new(&link
->dhcp_server
, link
->ifindex
);
333 r
= sd_dhcp_server_attach_event(link
->dhcp_server
, link
->manager
->event
, 0);
337 r
= sd_dhcp_server_set_callback(link
->dhcp_server
, dhcp_server_callback
, link
);
339 return log_link_warning_errno(link
, r
, "Failed to set callback for DHCPv4 server instance: %m");
341 r
= link_find_dhcp_server_address(link
, &address
);
343 return log_link_error_errno(link
, r
, "Failed to find suitable address for DHCPv4 server instance: %m");
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
);
349 return log_link_error_errno(link
, r
, "Failed to configure address pool for DHCPv4 server instance: %m");
352 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
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
));
361 return log_link_error_errno(link
, r
, "Failed to set maximum lease time for DHCPv4 server instance: %m");
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
));
368 return log_link_error_errno(link
, r
, "Failed to set default lease time for DHCPv4 server instance: %m");
371 for (sd_dhcp_lease_server_type_t type
= 0; type
< _SD_DHCP_LEASE_SERVER_TYPE_MAX
; type
++) {
373 if (!link
->network
->dhcp_server_emit
[type
].emit
)
376 if (link
->network
->dhcp_server_emit
[type
].n_addresses
> 0)
377 /* Explicitly specified servers to emit */
378 r
= sd_dhcp_server_set_servers(
381 link
->network
->dhcp_server_emit
[type
].addresses
,
382 link
->network
->dhcp_server_emit
[type
].n_addresses
);
384 /* Emission is requested, but nothing explicitly configured. Let's find a suitable upling */
385 if (!acquired_uplink
) {
386 (void) dhcp_server_find_uplink(link
, &uplink
);
387 acquired_uplink
= true;
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
);
396 "Not emitting %s on link, couldn't find suitable uplink.",
397 dhcp_lease_server_type_to_string(type
));
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
));
408 r
= sd_dhcp_server_set_emit_router(link
->dhcp_server
, link
->network
->dhcp_server_emit_router
);
410 return log_link_error_errno(link
, r
, "Failed to set router emission for DHCP server: %m");
412 r
= sd_dhcp_server_set_relay_target(link
->dhcp_server
, &link
->network
->dhcp_server_relay_target
);
414 return log_link_error_errno(link
, r
, "Failed to set relay target for DHCP server: %m");
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
);
419 return log_link_error_errno(link
, r
, "Failed to set interface binding for DHCP server: %m");
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
);
423 return log_link_error_errno(link
, r
, "Failed to set agent circuit/remote id for DHCP server: %m");
425 if (link
->network
->dhcp_server_emit_timezone
) {
426 _cleanup_free_
char *buffer
= NULL
;
427 const char *tz
= NULL
;
429 if (link
->network
->dhcp_server_timezone
)
430 tz
= link
->network
->dhcp_server_timezone
;
432 r
= get_timezone(&buffer
);
434 log_link_warning_errno(link
, r
, "Failed to determine timezone, not sending timezone: %m");
440 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
442 return log_link_error_errno(link
, r
, "Failed to set timezone for DHCP server: %m");
446 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
) {
447 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
451 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
454 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_vendor_options
) {
455 r
= sd_dhcp_server_add_vendor_option(link
->dhcp_server
, p
);
459 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
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
);
465 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 static lease for DHCP server: %m");
468 r
= sd_dhcp_server_start(link
->dhcp_server
);
470 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
472 log_link_debug(link
, "Offering DHCPv4 leases");
477 int link_request_dhcp_server(Link
*link
) {
480 if (!link_dhcp4_server_enabled(link
))
483 if (link
->dhcp_server
)
486 log_link_debug(link
, "Requesting DHCP server.");
487 return link_queue_request(link
, REQUEST_TYPE_DHCP_SERVER
, NULL
, false, NULL
, NULL
, NULL
);
490 static bool dhcp_server_is_ready_to_configure(Link
*link
) {
499 if (!IN_SET(link
->state
, LINK_STATE_CONFIGURING
, LINK_STATE_CONFIGURED
))
502 if (link
->set_flags_messages
> 0)
505 if (!link_has_carrier(link
))
508 if (link
->address_remove_messages
> 0)
511 if (!link
->static_addresses_configured
)
514 if (link_find_dhcp_server_address(link
, &a
) < 0)
517 if (!address_is_ready(a
))
520 if (dhcp_server_find_uplink(link
, &uplink
) < 0)
523 if (uplink
&& !uplink
->network
)
529 int request_process_dhcp_server(Request
*req
) {
532 assert(req
->type
== REQUEST_TYPE_DHCP_SERVER
);
534 if (!dhcp_server_is_ready_to_configure(req
->link
))
537 return dhcp4_server_configure(req
->link
);
540 int config_parse_dhcp_server_relay_agent_suboption(
542 const char *filename
,
545 unsigned section_line
,
552 char **suboption_value
= data
;
559 if (isempty(rvalue
)) {
560 *suboption_value
= mfree(*suboption_value
);
564 p
= startswith(rvalue
, "string:");
566 log_syntax(unit
, LOG_WARNING
, filename
, line
, 0,
567 "Failed to parse %s=%s'. Invalid format, ignoring.", lvalue
, rvalue
);
570 return free_and_strdup(suboption_value
, empty_to_null(p
));
573 int config_parse_dhcp_server_emit(
575 const char *filename
,
578 unsigned section_line
,
585 NetworkDHCPServerEmitAddress
*emit
= data
;
590 for (const char *p
= rvalue
;;) {
591 _cleanup_free_
char *w
= NULL
;
592 union in_addr_union a
;
595 r
= extract_first_word(&p
, &w
, NULL
, 0);
599 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
600 "Failed to extract word, ignoring: %s", rvalue
);
606 r
= in_addr_from_string(AF_INET
, w
, &a
);
608 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
609 "Failed to parse %s= address '%s', ignoring: %m", lvalue
, w
);
613 struct in_addr
*m
= reallocarray(emit
->addresses
, emit
->n_addresses
+ 1, sizeof(struct in_addr
));
618 emit
->addresses
[emit
->n_addresses
++] = a
.in
;
622 int config_parse_dhcp_server_address(
624 const char *filename
,
627 unsigned section_line
,
634 Network
*network
= userdata
;
635 union in_addr_union a
;
636 unsigned char prefixlen
;
643 if (isempty(rvalue
)) {
644 network
->dhcp_server_address
= (struct in_addr
) {};
645 network
->dhcp_server_address_prefixlen
= 0;
649 r
= in_addr_prefix_from_string(rvalue
, AF_INET
, &a
, &prefixlen
);
651 log_syntax(unit
, LOG_WARNING
, filename
, line
, r
,
652 "Failed to parse %s=, ignoring assignment: %s", lvalue
, rvalue
);
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
);
662 network
->dhcp_server_address
= a
.in
;
663 network
->dhcp_server_address_prefixlen
= prefixlen
;