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"
11 static Address
* link_find_dhcp_server_address(Link
*link
) {
15 assert(link
->network
);
17 /* The first statically configured address if there is any */
18 LIST_FOREACH(addresses
, address
, link
->network
->static_addresses
) {
20 if (address
->family
!= AF_INET
)
23 if (in_addr_is_null(address
->family
, &address
->in_addr
))
29 /* If that didn't work, find a suitable address we got from the pool */
30 LIST_FOREACH(addresses
, address
, link
->pool_addresses
) {
31 if (address
->family
!= AF_INET
)
40 static int link_push_uplink_dns_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
41 _cleanup_free_
struct in_addr
*addresses
= NULL
;
42 size_t n_addresses
= 0, n_allocated
= 0;
45 log_debug("Copying DNS server information from %s", link
->ifname
);
50 for (i
= 0; i
< link
->network
->n_dns
; i
++) {
53 /* Only look for IPv4 addresses */
54 if (link
->network
->dns
[i
].family
!= AF_INET
)
57 ia
= link
->network
->dns
[i
].address
.in
;
59 /* Never propagate obviously borked data */
60 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
63 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
66 addresses
[n_addresses
++] = ia
;
69 if (link
->network
->dhcp_use_dns
&& link
->dhcp_lease
) {
70 const struct in_addr
*da
= NULL
;
73 n
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &da
);
76 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
79 for (j
= 0; j
< n
; j
++)
80 if (in4_addr_is_non_local(&da
[j
]))
81 addresses
[n_addresses
++] = da
[j
];
88 return sd_dhcp_server_set_dns(s
, addresses
, n_addresses
);
91 static int link_push_uplink_ntp_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
92 _cleanup_free_
struct in_addr
*addresses
= NULL
;
93 size_t n_addresses
= 0, n_allocated
= 0;
99 log_debug("Copying NTP server information from %s", link
->ifname
);
101 STRV_FOREACH(a
, link
->network
->ntp
) {
102 union in_addr_union ia
;
104 /* Only look for IPv4 addresses */
105 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
108 /* Never propagate obviously borked data */
109 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
112 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
115 addresses
[n_addresses
++] = ia
.in
;
118 if (link
->network
->dhcp_use_ntp
&& link
->dhcp_lease
) {
119 const struct in_addr
*da
= NULL
;
122 n
= sd_dhcp_lease_get_ntp(link
->dhcp_lease
, &da
);
125 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
128 for (j
= 0; j
< n
; j
++)
129 if (in4_addr_is_non_local(&da
[j
]))
130 addresses
[n_addresses
++] = da
[j
];
134 if (n_addresses
<= 0)
137 return sd_dhcp_server_set_ntp(s
, addresses
, n_addresses
);
140 static int link_push_uplink_sip_to_dhcp_server(Link
*link
, sd_dhcp_server
*s
) {
141 _cleanup_free_
struct in_addr
*addresses
= NULL
;
142 size_t n_addresses
= 0, n_allocated
= 0;
148 log_debug("Copying SIP server information from %s", link
->ifname
);
150 STRV_FOREACH(a
, link
->network
->sip
) {
151 union in_addr_union ia
;
153 /* Only look for IPv4 addresses */
154 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
157 /* Never propagate obviously borked data */
158 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
161 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
164 addresses
[n_addresses
++] = ia
.in
;
167 if (link
->network
->dhcp_use_sip
&& link
->dhcp_lease
) {
168 const struct in_addr
*da
= NULL
;
171 n
= sd_dhcp_lease_get_sip(link
->dhcp_lease
, &da
);
174 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
177 for (j
= 0; j
< n
; j
++)
178 if (in4_addr_is_non_local(&da
[j
]))
179 addresses
[n_addresses
++] = da
[j
];
183 if (n_addresses
<= 0)
186 return sd_dhcp_server_set_sip(s
, addresses
, n_addresses
);
189 int dhcp4_server_configure(Link
*link
) {
192 bool acquired_uplink
= false;
195 address
= link_find_dhcp_server_address(link
);
197 return log_link_warning_errno(link
, SYNTHETIC_ERRNO(EBUSY
),
198 "Failed to find suitable address for DHCPv4 server instance.");
200 /* use the server address' subnet as the pool */
201 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
202 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
207 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
212 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
213 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
,
214 DIV_ROUND_UP(link
->network
->dhcp_server_max_lease_time_usec
, USEC_PER_SEC
));
219 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
220 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
,
221 DIV_ROUND_UP(link
->network
->dhcp_server_default_lease_time_usec
, USEC_PER_SEC
));
226 if (link
->network
->dhcp_server_emit_dns
) {
227 if (link
->network
->n_dhcp_server_dns
> 0)
228 r
= sd_dhcp_server_set_dns(link
->dhcp_server
, link
->network
->dhcp_server_dns
, link
->network
->n_dhcp_server_dns
);
230 uplink
= manager_find_uplink(link
->manager
, link
);
231 acquired_uplink
= true;
234 log_link_debug(link
, "Not emitting DNS server information on link, couldn't find suitable uplink.");
237 r
= link_push_uplink_dns_to_dhcp_server(uplink
, link
->dhcp_server
);
240 log_link_warning_errno(link
, r
, "Failed to set DNS server for DHCP server, ignoring: %m");
243 if (link
->network
->dhcp_server_emit_ntp
) {
244 if (link
->network
->n_dhcp_server_ntp
> 0)
245 r
= sd_dhcp_server_set_ntp(link
->dhcp_server
, link
->network
->dhcp_server_ntp
, link
->network
->n_dhcp_server_ntp
);
247 if (!acquired_uplink
)
248 uplink
= manager_find_uplink(link
->manager
, link
);
251 log_link_debug(link
, "Not emitting NTP server information on link, couldn't find suitable uplink.");
254 r
= link_push_uplink_ntp_to_dhcp_server(uplink
, link
->dhcp_server
);
258 log_link_warning_errno(link
, r
, "Failed to set NTP server for DHCP server, ignoring: %m");
261 if (link
->network
->dhcp_server_emit_sip
) {
262 if (link
->network
->n_dhcp_server_sip
> 0)
263 r
= sd_dhcp_server_set_sip(link
->dhcp_server
, link
->network
->dhcp_server_sip
, link
->network
->n_dhcp_server_sip
);
265 if (!acquired_uplink
)
266 uplink
= manager_find_uplink(link
->manager
, link
);
269 log_link_debug(link
, "Not emitting sip server information on link, couldn't find suitable uplink.");
272 r
= link_push_uplink_sip_to_dhcp_server(uplink
, link
->dhcp_server
);
276 log_link_warning_errno(link
, r
, "Failed to set SIP server for DHCP server, ignoring: %m");
279 r
= sd_dhcp_server_set_emit_router(link
->dhcp_server
, link
->network
->dhcp_server_emit_router
);
281 return log_link_warning_errno(link
, r
, "Failed to set router emission for DHCP server: %m");
283 if (link
->network
->dhcp_server_emit_timezone
) {
284 _cleanup_free_
char *buffer
= NULL
;
287 if (link
->network
->dhcp_server_timezone
)
288 tz
= link
->network
->dhcp_server_timezone
;
290 r
= get_timezone(&buffer
);
292 return log_warning_errno(r
, "Failed to determine timezone: %m");
297 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
301 if (!sd_dhcp_server_is_running(link
->dhcp_server
)) {
302 r
= sd_dhcp_server_start(link
->dhcp_server
);
304 return log_link_warning_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
310 int config_parse_dhcp_server_dns(
312 const char *filename
,
315 unsigned section_line
,
323 const char *p
= rvalue
;
331 _cleanup_free_
char *w
= NULL
;
332 union in_addr_union a
;
335 r
= extract_first_word(&p
, &w
, NULL
, 0);
339 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
340 "Failed to extract word, ignoring: %s", rvalue
);
346 r
= in_addr_from_string(AF_INET
, w
, &a
);
348 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
349 "Failed to parse DNS server address '%s', ignoring assignment: %m", w
);
353 m
= reallocarray(n
->dhcp_server_dns
, n
->n_dhcp_server_dns
+ 1, sizeof(struct in_addr
));
357 m
[n
->n_dhcp_server_dns
++] = a
.in
;
358 n
->dhcp_server_dns
= m
;
364 int config_parse_dhcp_server_ntp(
366 const char *filename
,
369 unsigned section_line
,
377 const char *p
= rvalue
;
385 _cleanup_free_
char *w
= NULL
;
386 union in_addr_union a
;
389 r
= extract_first_word(&p
, &w
, NULL
, 0);
393 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
394 "Failed to extract word, ignoring: %s", rvalue
);
400 r
= in_addr_from_string(AF_INET
, w
, &a
);
402 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
403 "Failed to parse NTP server address '%s', ignoring: %m", w
);
407 m
= reallocarray(n
->dhcp_server_ntp
, n
->n_dhcp_server_ntp
+ 1, sizeof(struct in_addr
));
411 m
[n
->n_dhcp_server_ntp
++] = a
.in
;
412 n
->dhcp_server_ntp
= m
;
416 int config_parse_dhcp_server_sip(
418 const char *filename
,
421 unsigned section_line
,
429 const char *p
= rvalue
;
437 _cleanup_free_
char *w
= NULL
;
438 union in_addr_union a
;
441 r
= extract_first_word(&p
, &w
, NULL
, 0);
445 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
446 "Failed to extract word, ignoring: %s", rvalue
);
452 r
= in_addr_from_string(AF_INET
, w
, &a
);
454 log_syntax(unit
, LOG_ERR
, filename
, line
, r
,
455 "Failed to parse SIP server address '%s', ignoring: %m", w
);
459 m
= reallocarray(n
->dhcp_server_sip
, n
->n_dhcp_server_sip
+ 1, sizeof(struct in_addr
));
463 m
[n
->n_dhcp_server_sip
++] = a
.in
;
464 n
->dhcp_server_sip
= m
;