1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 #include "sd-dhcp-server.h"
5 #include "networkd-dhcp-server.h"
6 #include "networkd-link.h"
7 #include "networkd-manager.h"
8 #include "networkd-network.h"
9 #include "parse-util.h"
11 #include "string-table.h"
12 #include "string-util.h"
14 static Address
* link_find_dhcp_server_address(Link
*link
) {
18 assert(link
->network
);
20 /* The first statically configured address if there is any */
21 LIST_FOREACH(addresses
, address
, link
->network
->static_addresses
) {
23 if (address
->family
!= AF_INET
)
26 if (in_addr_is_null(address
->family
, &address
->in_addr
))
32 /* If that didn't work, find a suitable address we got from the pool */
33 LIST_FOREACH(addresses
, address
, link
->pool_addresses
) {
34 if (address
->family
!= AF_INET
)
43 static int link_push_uplink_dns_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
44 _cleanup_free_
struct in_addr
*addresses
= NULL
;
45 size_t n_addresses
= 0, n_allocated
= 0;
48 log_debug("Copying DNS server information from %s", link
->ifname
);
53 for (i
= 0; i
< link
->network
->n_dns
; i
++) {
56 /* Only look for IPv4 addresses */
57 if (link
->network
->dns
[i
].family
!= AF_INET
)
60 ia
= link
->network
->dns
[i
].address
.in
;
62 /* Never propagate obviously borked data */
63 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
66 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
69 addresses
[n_addresses
++] = ia
;
72 if (link
->network
->dhcp_use_dns
&& link
->dhcp_lease
) {
73 const struct in_addr
*da
= NULL
;
76 n
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &da
);
79 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
82 for (j
= 0; j
< n
; j
++)
83 if (in4_addr_is_non_local(&da
[j
]))
84 addresses
[n_addresses
++] = da
[j
];
91 return sd_dhcp_server_set_dns(s
, addresses
, n_addresses
);
94 static int link_push_uplink_ntp_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
95 _cleanup_free_
struct in_addr
*addresses
= NULL
;
96 size_t n_addresses
= 0, n_allocated
= 0;
102 log_debug("Copying NTP server information from %s", link
->ifname
);
104 STRV_FOREACH(a
, link
->network
->ntp
) {
105 union in_addr_union ia
;
107 /* Only look for IPv4 addresses */
108 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
111 /* Never propagate obviously borked data */
112 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
115 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
118 addresses
[n_addresses
++] = ia
.in
;
121 if (link
->network
->dhcp_use_ntp
&& link
->dhcp_lease
) {
122 const struct in_addr
*da
= NULL
;
125 n
= sd_dhcp_lease_get_ntp(link
->dhcp_lease
, &da
);
128 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
131 for (j
= 0; j
< n
; j
++)
132 if (in4_addr_is_non_local(&da
[j
]))
133 addresses
[n_addresses
++] = da
[j
];
137 if (n_addresses
<= 0)
140 return sd_dhcp_server_set_ntp(s
, addresses
, n_addresses
);
143 static int link_push_uplink_sip_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
144 _cleanup_free_
struct in_addr
*addresses
= NULL
;
145 size_t n_addresses
= 0, n_allocated
= 0;
151 log_debug("Copying SIP server information from %s", link
->ifname
);
153 STRV_FOREACH(a
, link
->network
->sip
) {
154 union in_addr_union ia
;
156 /* Only look for IPv4 addresses */
157 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
160 /* Never propagate obviously borked data */
161 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
164 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
167 addresses
[n_addresses
++] = ia
.in
;
170 if (link
->network
->dhcp_use_sip
&& link
->dhcp_lease
) {
171 const struct in_addr
*da
= NULL
;
174 n
= sd_dhcp_lease_get_sip(link
->dhcp_lease
, &da
);
177 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
180 for (j
= 0; j
< n
; j
++)
181 if (in4_addr_is_non_local(&da
[j
]))
182 addresses
[n_addresses
++] = da
[j
];
186 if (n_addresses
<= 0)
189 return sd_dhcp_server_set_sip(s
, addresses
, n_addresses
);
192 int dhcp4_server_configure(Link
*link
) {
193 bool acquired_uplink
= false;
200 address
= link_find_dhcp_server_address(link
);
202 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBUSY
),
203 "Failed to find suitable address for DHCPv4 server instance.");
205 /* use the server address' subnet as the pool */
206 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
207 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
212 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
217 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
218 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
,
219 DIV_ROUND_UP(link
->network
->dhcp_server_max_lease_time_usec
, USEC_PER_SEC
));
224 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
225 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
,
226 DIV_ROUND_UP(link
->network
->dhcp_server_default_lease_time_usec
, USEC_PER_SEC
));
231 if (link
->network
->dhcp_server_emit_dns
) {
232 if (link
->network
->n_dhcp_server_dns
> 0)
233 r
= sd_dhcp_server_set_dns(link
->dhcp_server
, link
->network
->dhcp_server_dns
, link
->network
->n_dhcp_server_dns
);
235 uplink
= manager_find_uplink(link
->manager
, link
);
236 acquired_uplink
= true;
239 log_link_debug(link
, "Not emitting DNS server information on link, couldn't find suitable uplink.");
242 r
= link_push_uplink_dns_to_dhcp_server(uplink
, link
->dhcp_server
);
245 log_link_warning_errno(link
, r
, "Failed to set DNS server for DHCP server, ignoring: %m");
248 if (link
->network
->dhcp_server_emit_ntp
) {
249 if (link
->network
->n_dhcp_server_ntp
> 0)
250 r
= sd_dhcp_server_set_ntp(link
->dhcp_server
, link
->network
->dhcp_server_ntp
, link
->network
->n_dhcp_server_ntp
);
252 if (!acquired_uplink
)
253 uplink
= manager_find_uplink(link
->manager
, link
);
256 log_link_debug(link
, "Not emitting NTP server information on link, couldn't find suitable uplink.");
259 r
= link_push_uplink_ntp_to_dhcp_server(uplink
, link
->dhcp_server
);
263 log_link_warning_errno(link
, r
, "Failed to set NTP server for DHCP server, ignoring: %m");
266 if (link
->network
->dhcp_server_emit_sip
) {
267 if (link
->network
->n_dhcp_server_sip
> 0)
268 r
= sd_dhcp_server_set_sip(link
->dhcp_server
, link
->network
->dhcp_server_sip
, link
->network
->n_dhcp_server_sip
);
270 if (!acquired_uplink
)
271 uplink
= manager_find_uplink(link
->manager
, link
);
274 log_link_debug(link
, "Not emitting sip server information on link, couldn't find suitable uplink.");
277 r
= link_push_uplink_sip_to_dhcp_server(uplink
, link
->dhcp_server
);
281 log_link_warning_errno(link
, r
, "Failed to set SIP server for DHCP server, ignoring: %m");
284 r
= sd_dhcp_server_set_emit_router(link
->dhcp_server
, link
->network
->dhcp_server_emit_router
);
286 return log_link_error_errno(link
, r
, "Failed to set router emission for DHCP server: %m");
288 if (link
->network
->dhcp_server_emit_timezone
) {
289 _cleanup_free_
char *buffer
= NULL
;
292 if (link
->network
->dhcp_server_timezone
)
293 tz
= link
->network
->dhcp_server_timezone
;
295 r
= get_timezone(&buffer
);
297 return log_error_errno(r
, "Failed to determine timezone: %m");
302 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
307 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
, i
) {
308 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
315 if (!sd_dhcp_server_is_running(link
->dhcp_server
)) {
316 r
= sd_dhcp_server_start(link
->dhcp_server
);
318 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
324 int config_parse_dhcp_server_dns(
326 const char *filename
,
329 unsigned section_line
,
337 const char *p
= rvalue
;
345 _cleanup_free_
char *w
= NULL
;
346 union in_addr_union a
;
349 r
= extract_first_word(&p
, &w
, NULL
, 0);
353 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
354 "Failed to extract word, ignoring: %s", rvalue
);
360 r
= in_addr_from_string(AF_INET
, w
, &a
);
362 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
363 "Failed to parse DNS server address '%s', ignoring assignment: %m", w
);
367 m
= reallocarray(n
->dhcp_server_dns
, n
->n_dhcp_server_dns
+ 1, sizeof(struct in_addr
));
371 m
[n
->n_dhcp_server_dns
++] = a
.in
;
372 n
->dhcp_server_dns
= m
;
378 int config_parse_dhcp_server_ntp(
380 const char *filename
,
383 unsigned section_line
,
391 const char *p
= rvalue
;
399 _cleanup_free_
char *w
= NULL
;
400 union in_addr_union a
;
403 r
= extract_first_word(&p
, &w
, NULL
, 0);
407 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
408 "Failed to extract word, ignoring: %s", rvalue
);
414 r
= in_addr_from_string(AF_INET
, w
, &a
);
416 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
417 "Failed to parse NTP server address '%s', ignoring: %m", w
);
421 m
= reallocarray(n
->dhcp_server_ntp
, n
->n_dhcp_server_ntp
+ 1, sizeof(struct in_addr
));
425 m
[n
->n_dhcp_server_ntp
++] = a
.in
;
426 n
->dhcp_server_ntp
= m
;
430 int config_parse_dhcp_server_sip(
432 const char *filename
,
435 unsigned section_line
,
443 const char *p
= rvalue
;
451 _cleanup_free_
char *w
= NULL
;
452 union in_addr_union a
;
455 r
= extract_first_word(&p
, &w
, NULL
, 0);
459 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
460 "Failed to extract word, ignoring: %s", rvalue
);
466 r
= in_addr_from_string(AF_INET
, w
, &a
);
468 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
469 "Failed to parse SIP server address '%s', ignoring: %m", w
);
473 m
= reallocarray(n
->dhcp_server_sip
, n
->n_dhcp_server_sip
+ 1, sizeof(struct in_addr
));
477 m
[n
->n_dhcp_server_sip
++] = a
.in
;
478 n
->dhcp_server_sip
= m
;