1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "sd-dhcp-server.h"
7 #include "networkd-dhcp-server.h"
8 #include "networkd-link.h"
9 #include "networkd-manager.h"
10 #include "networkd-network.h"
11 #include "parse-util.h"
12 #include "socket-netlink.h"
13 #include "string-table.h"
14 #include "string-util.h"
17 static Address
* link_find_dhcp_server_address(Link
*link
) {
21 assert(link
->network
);
23 /* The first statically configured address if there is any */
24 LIST_FOREACH(addresses
, address
, link
->network
->static_addresses
) {
26 if (address
->family
!= AF_INET
)
29 if (in_addr_is_null(address
->family
, &address
->in_addr
))
35 /* If that didn't work, find a suitable address we got from the pool */
36 LIST_FOREACH(addresses
, address
, link
->pool_addresses
) {
37 if (address
->family
!= AF_INET
)
46 static int link_push_uplink_dns_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
47 _cleanup_free_
struct in_addr
*addresses
= NULL
;
48 size_t n_addresses
= 0, n_allocated
= 0;
51 for (i
= 0; i
< link
->network
->n_dns
; i
++) {
54 /* Only look for IPv4 addresses */
55 if (link
->network
->dns
[i
].family
!= AF_INET
)
58 ia
= link
->network
->dns
[i
].address
.in
;
60 /* Never propagate obviously borked data */
61 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
64 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
67 addresses
[n_addresses
++] = ia
;
70 if (link
->network
->dhcp_use_dns
&& link
->dhcp_lease
) {
71 const struct in_addr
*da
= NULL
;
74 n
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &da
);
77 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
80 for (j
= 0; j
< n
; j
++)
81 if (in4_addr_is_non_local(&da
[j
]))
82 addresses
[n_addresses
++] = da
[j
];
89 return sd_dhcp_server_set_dns(s
, addresses
, n_addresses
);
92 static int link_push_uplink_to_dhcp_server(
94 sd_dhcp_lease_info what
,
97 _cleanup_free_
struct in_addr
*addresses
= NULL
;
98 size_t n_addresses
= 0, n_allocated
= 0;
105 log_link_debug(link
, "Copying %s from link", dhcp_lease_info_to_string(what
));
108 case SD_DHCP_LEASE_DNS_SERVERS
:
109 /* DNS servers are stored as parsed data, so special handling is required.
110 * TODO: check if DNS servers should be stored unparsed too. */
111 return link_push_uplink_dns_to_dhcp_server(link
, s
);
113 case SD_DHCP_LEASE_NTP_SERVERS
:
114 servers
= link
->network
->ntp
;
115 lease_condition
= link
->network
->dhcp_use_ntp
;
118 case SD_DHCP_LEASE_POP3_SERVERS
:
119 servers
= link
->network
->pop3
;
120 lease_condition
= true;
123 case SD_DHCP_LEASE_SMTP_SERVERS
:
124 servers
= link
->network
->smtp
;
125 lease_condition
= true;
128 case SD_DHCP_LEASE_SIP_SERVERS
:
129 servers
= link
->network
->sip
;
130 lease_condition
= link
->network
->dhcp_use_sip
;
133 case SD_DHCP_LEASE_LPR_SERVERS
:
134 servers
= link
->network
->lpr
;
135 lease_condition
= true;
139 assert_not_reached("Unknown DHCP lease info item");
143 STRV_FOREACH(a
, servers
) {
144 union in_addr_union ia
;
146 /* Only look for IPv4 addresses */
147 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
150 /* Never propagate obviously borked data */
151 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
154 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
157 addresses
[n_addresses
++] = ia
.in
;
160 if (lease_condition
&& link
->dhcp_lease
) {
161 const struct in_addr
*da
;
163 size_t n
= sd_dhcp_lease_get_servers(link
->dhcp_lease
, what
, &da
);
165 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
168 for (unsigned i
= 0; i
< n
; i
++)
169 if (in4_addr_is_non_local(&da
[i
]))
170 addresses
[n_addresses
++] = da
[i
];
174 if (n_addresses
<= 0)
177 return sd_dhcp_server_set_servers(s
, what
, addresses
, n_addresses
);
180 static int dhcp4_server_parse_dns_server_string_and_warn(Link
*l
, const char *string
, struct in_addr
**addresses
, size_t *n_allocated
, size_t *n_addresses
) {
182 _cleanup_free_
char *word
= NULL
, *server_name
= NULL
;
183 union in_addr_union address
;
184 int family
, r
, ifindex
= 0;
186 r
= extract_first_word(&string
, &word
, NULL
, 0);
192 r
= in_addr_ifindex_name_from_string_auto(word
, &family
, &address
, &ifindex
, &server_name
);
194 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring: %m", word
);
198 /* Only look for IPv4 addresses */
199 if (family
!= AF_INET
)
202 /* Never propagate obviously borked data */
203 if (in4_addr_is_null(&address
.in
) || in4_addr_is_localhost(&address
.in
))
206 if (!GREEDY_REALLOC(*addresses
, *n_allocated
, *n_addresses
+ 1))
209 (*addresses
)[(*n_addresses
)++] = address
.in
;
215 static int dhcp4_server_set_dns_from_resolve_conf(Link
*link
) {
216 _cleanup_free_
struct in_addr
*addresses
= NULL
;
217 size_t n_addresses
= 0, n_allocated
= 0;
218 _cleanup_fclose_
FILE *f
= NULL
;
221 f
= fopen(PRIVATE_UPLINK_RESOLV_CONF
, "re");
226 return log_warning_errno(errno
, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF
": %m");
230 _cleanup_free_
char *line
= NULL
;
234 r
= read_line(f
, LONG_LINE_MAX
, &line
);
236 return log_error_errno(r
, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF
": %m");
243 if (IN_SET(*l
, '#', ';', 0))
246 a
= first_word(l
, "nameserver");
250 r
= dhcp4_server_parse_dns_server_string_and_warn(link
, a
, &addresses
, &n_allocated
, &n_addresses
);
252 log_warning_errno(r
, "Failed to parse DNS server address '%s', ignoring.", a
);
255 if (n_addresses
<= 0)
258 return sd_dhcp_server_set_dns(link
->dhcp_server
, addresses
, n_addresses
);
261 int dhcp4_server_configure(Link
*link
) {
262 bool acquired_uplink
= false;
269 address
= link_find_dhcp_server_address(link
);
271 return log_link_error_errno(link
, SYNTHETIC_ERRNO(EBUSY
),
272 "Failed to find suitable address for DHCPv4 server instance.");
274 /* use the server address' subnet as the pool */
275 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
276 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
278 return log_link_error_errno(link
, r
, "Failed to configure address pool for DHCPv4 server instance: %m");
281 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
286 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
287 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
,
288 DIV_ROUND_UP(link
->network
->dhcp_server_max_lease_time_usec
, USEC_PER_SEC
));
290 return log_link_error_errno(link
, r
, "Failed to set maximum lease time for DHCPv4 server instance: %m");
293 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
294 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
,
295 DIV_ROUND_UP(link
->network
->dhcp_server_default_lease_time_usec
, USEC_PER_SEC
));
297 return log_link_error_errno(link
, r
, "Failed to set default lease time for DHCPv4 server instance: %m");
302 const struct in_addr
*servers
;
305 [SD_DHCP_LEASE_DNS_SERVERS
] = {
306 link
->network
->dhcp_server_emit_dns
,
307 link
->network
->dhcp_server_dns
,
308 link
->network
->n_dhcp_server_dns
,
310 [SD_DHCP_LEASE_NTP_SERVERS
] = {
311 link
->network
->dhcp_server_emit_ntp
,
312 link
->network
->dhcp_server_ntp
,
313 link
->network
->n_dhcp_server_ntp
,
315 [SD_DHCP_LEASE_SIP_SERVERS
] = {
316 link
->network
->dhcp_server_emit_sip
,
317 link
->network
->dhcp_server_sip
,
318 link
->network
->n_dhcp_server_sip
,
320 [SD_DHCP_LEASE_POP3_SERVERS
] = {
322 link
->network
->dhcp_server_pop3
,
323 link
->network
->n_dhcp_server_pop3
,
325 [SD_DHCP_LEASE_SMTP_SERVERS
] = {
327 link
->network
->dhcp_server_smtp
,
328 link
->network
->n_dhcp_server_smtp
,
330 [SD_DHCP_LEASE_LPR_SERVERS
] = {
332 link
->network
->dhcp_server_lpr
,
333 link
->network
->n_dhcp_server_lpr
,
336 assert_cc(ELEMENTSOF(configs
) == _SD_DHCP_LEASE_INFO_MAX
);
338 for (unsigned n
= 0; n
< ELEMENTSOF(configs
); n
++)
339 if (configs
[n
].condition
) {
340 if (configs
[n
].n_servers
> 0)
341 r
= sd_dhcp_server_set_servers(link
->dhcp_server
, n
,
342 configs
[n
].servers
, configs
[n
].n_servers
);
344 if (!acquired_uplink
) {
345 uplink
= manager_find_uplink(link
->manager
, link
);
346 acquired_uplink
= true;
351 "Not emitting %s on link, couldn't find suitable uplink.",
352 dhcp_lease_info_to_string(n
));
354 } else if (uplink
->network
)
355 r
= link_push_uplink_to_dhcp_server(uplink
, n
, link
->dhcp_server
);
356 else if (n
== SD_DHCP_LEASE_DNS_SERVERS
)
357 r
= dhcp4_server_set_dns_from_resolve_conf(link
);
360 log_link_warning_errno(link
, r
,
361 "Failed to set %s for DHCP server, ignoring: %m",
362 dhcp_lease_info_to_string(n
));
365 r
= sd_dhcp_server_set_emit_router(link
->dhcp_server
, link
->network
->dhcp_server_emit_router
);
367 return log_link_error_errno(link
, r
, "Failed to set router emission for DHCP server: %m");
369 if (link
->network
->dhcp_server_emit_timezone
) {
370 _cleanup_free_
char *buffer
= NULL
;
373 if (link
->network
->dhcp_server_timezone
)
374 tz
= link
->network
->dhcp_server_timezone
;
376 r
= get_timezone(&buffer
);
378 return log_link_error_errno(link
, r
, "Failed to determine timezone: %m");
383 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
385 return log_link_error_errno(link
, r
, "Failed to set timezone for DHCP server: %m");
388 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
, i
) {
389 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
393 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
396 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_vendor_options
, i
) {
397 r
= sd_dhcp_server_add_vendor_option(link
->dhcp_server
, p
);
401 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
404 if (!sd_dhcp_server_is_running(link
->dhcp_server
)) {
405 r
= sd_dhcp_server_start(link
->dhcp_server
);
407 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
413 static int config_parse_dhcp_lease_server_list(
415 const char *filename
,
419 struct in_addr
**addresses
,
420 unsigned *n_addresses
) {
426 for (const char *p
= rvalue
;;) {
427 _cleanup_free_
char *w
= NULL
;
428 union in_addr_union a
;
431 r
= extract_first_word(&p
, &w
, NULL
, 0);
435 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
436 "Failed to extract word, ignoring: %s", rvalue
);
442 r
= in_addr_from_string(AF_INET
, w
, &a
);
444 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
445 "Failed to parse %s= address '%s', ignoring: %m", lvalue
, w
);
449 struct in_addr
*m
= reallocarray(*addresses
, *n_addresses
+ 1, sizeof(struct in_addr
));
453 m
[(*n_addresses
)++] = a
.in
;
458 int config_parse_dhcp_server_dns(
460 const char *filename
,
463 unsigned section_line
,
472 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
474 &n
->dhcp_server_dns
, &n
->n_dhcp_server_dns
);
477 int config_parse_dhcp_server_ntp(
479 const char *filename
,
482 unsigned section_line
,
491 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
493 &n
->dhcp_server_ntp
, &n
->n_dhcp_server_ntp
);
496 int config_parse_dhcp_server_sip(
498 const char *filename
,
501 unsigned section_line
,
510 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
512 &n
->dhcp_server_sip
, &n
->n_dhcp_server_sip
);
515 int config_parse_dhcp_server_pop3_servers(
517 const char *filename
,
520 unsigned section_line
,
529 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
531 &n
->dhcp_server_pop3
, &n
->n_dhcp_server_pop3
);
534 int config_parse_dhcp_server_smtp_servers(
536 const char *filename
,
539 unsigned section_line
,
548 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
550 &n
->dhcp_server_smtp
, &n
->n_dhcp_server_smtp
);
554 int config_parse_dhcp_server_lpr_servers(
556 const char *filename
,
559 unsigned section_line
,
568 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
570 &n
->dhcp_server_lpr
, &n
->n_dhcp_server_lpr
);