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 for (i
= 0; i
< link
->network
->n_dns
; i
++) {
51 /* Only look for IPv4 addresses */
52 if (link
->network
->dns
[i
].family
!= AF_INET
)
55 ia
= link
->network
->dns
[i
].address
.in
;
57 /* Never propagate obviously borked data */
58 if (in4_addr_is_null(&ia
) || in4_addr_is_localhost(&ia
))
61 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
64 addresses
[n_addresses
++] = ia
;
67 if (link
->network
->dhcp_use_dns
&& link
->dhcp_lease
) {
68 const struct in_addr
*da
= NULL
;
71 n
= sd_dhcp_lease_get_dns(link
->dhcp_lease
, &da
);
74 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
77 for (j
= 0; j
< n
; j
++)
78 if (in4_addr_is_non_local(&da
[j
]))
79 addresses
[n_addresses
++] = da
[j
];
86 return sd_dhcp_server_set_dns(s
, addresses
, n_addresses
);
89 static int link_push_uplink_to_dhcp_server(
91 sd_dhcp_lease_info what
,
94 _cleanup_free_
struct in_addr
*addresses
= NULL
;
95 size_t n_addresses
= 0, n_allocated
= 0;
102 log_link_debug(link
, "Copying %s from link", dhcp_lease_info_to_string(what
));
105 case SD_DHCP_LEASE_DNS_SERVERS
:
106 /* DNS servers are stored as parsed data, so special handling is required.
107 * TODO: check if DNS servers should be stored unparsed too. */
108 return link_push_uplink_dns_to_dhcp_server(link
, s
);
110 case SD_DHCP_LEASE_NTP_SERVERS
:
111 servers
= link
->network
->ntp
;
112 lease_condition
= link
->network
->dhcp_use_ntp
;
115 case SD_DHCP_LEASE_POP3_SERVERS
:
116 servers
= link
->network
->pop3
;
117 lease_condition
= true;
120 case SD_DHCP_LEASE_SMTP_SERVERS
:
121 servers
= link
->network
->smtp
;
122 lease_condition
= true;
125 case SD_DHCP_LEASE_SIP_SERVERS
:
126 servers
= link
->network
->sip
;
127 lease_condition
= link
->network
->dhcp_use_sip
;
131 assert_not_reached("Unknown DHCP lease info item");
135 STRV_FOREACH(a
, servers
) {
136 union in_addr_union ia
;
138 /* Only look for IPv4 addresses */
139 if (in_addr_from_string(AF_INET
, *a
, &ia
) <= 0)
142 /* Never propagate obviously borked data */
143 if (in4_addr_is_null(&ia
.in
) || in4_addr_is_localhost(&ia
.in
))
146 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ 1))
149 addresses
[n_addresses
++] = ia
.in
;
152 if (lease_condition
&& link
->dhcp_lease
) {
153 const struct in_addr
*da
;
155 size_t n
= sd_dhcp_lease_get_servers(link
->dhcp_lease
, what
, &da
);
157 if (!GREEDY_REALLOC(addresses
, n_allocated
, n_addresses
+ n
))
160 for (unsigned i
= 0; i
< n
; i
++)
161 if (in4_addr_is_non_local(&da
[i
]))
162 addresses
[n_addresses
++] = da
[i
];
166 if (n_addresses
<= 0)
169 return sd_dhcp_server_set_servers(s
, what
, addresses
, n_addresses
);
172 int dhcp4_server_configure(Link
*link
) {
173 bool acquired_uplink
= false;
180 address
= link_find_dhcp_server_address(link
);
182 return log_link_error_errno(link
, SYNTHETIC_ERRNO(EBUSY
),
183 "Failed to find suitable address for DHCPv4 server instance.");
185 /* use the server address' subnet as the pool */
186 r
= sd_dhcp_server_configure_pool(link
->dhcp_server
, &address
->in_addr
.in
, address
->prefixlen
,
187 link
->network
->dhcp_server_pool_offset
, link
->network
->dhcp_server_pool_size
);
189 return log_link_error_errno(link
, r
, "Failed to configure address pool for DHCPv4 server instance: %m");
192 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
197 if (link
->network
->dhcp_server_max_lease_time_usec
> 0) {
198 r
= sd_dhcp_server_set_max_lease_time(link
->dhcp_server
,
199 DIV_ROUND_UP(link
->network
->dhcp_server_max_lease_time_usec
, USEC_PER_SEC
));
201 return log_link_error_errno(link
, r
, "Failed to set maximum lease time for DHCPv4 server instance: %m");
204 if (link
->network
->dhcp_server_default_lease_time_usec
> 0) {
205 r
= sd_dhcp_server_set_default_lease_time(link
->dhcp_server
,
206 DIV_ROUND_UP(link
->network
->dhcp_server_default_lease_time_usec
, USEC_PER_SEC
));
208 return log_link_error_errno(link
, r
, "Failed to set default lease time for DHCPv4 server instance: %m");
213 const struct in_addr
*servers
;
216 [SD_DHCP_LEASE_DNS_SERVERS
] = {
217 link
->network
->dhcp_server_emit_dns
,
218 link
->network
->dhcp_server_dns
,
219 link
->network
->n_dhcp_server_dns
,
221 [SD_DHCP_LEASE_NTP_SERVERS
] = {
222 link
->network
->dhcp_server_emit_ntp
,
223 link
->network
->dhcp_server_ntp
,
224 link
->network
->n_dhcp_server_ntp
,
226 [SD_DHCP_LEASE_SIP_SERVERS
] = {
227 link
->network
->dhcp_server_emit_sip
,
228 link
->network
->dhcp_server_sip
,
229 link
->network
->n_dhcp_server_sip
,
231 [SD_DHCP_LEASE_POP3_SERVERS
] = {
233 link
->network
->dhcp_server_pop3
,
234 link
->network
->n_dhcp_server_pop3
,
236 [SD_DHCP_LEASE_SMTP_SERVERS
] = {
238 link
->network
->dhcp_server_smtp
,
239 link
->network
->n_dhcp_server_smtp
,
242 assert_cc(ELEMENTSOF(configs
) == _SD_DHCP_LEASE_INFO_MAX
);
244 for (unsigned n
= 0; n
< ELEMENTSOF(configs
); n
++)
245 if (configs
[n
].condition
) {
246 if (configs
[n
].n_servers
> 0)
247 r
= sd_dhcp_server_set_servers(link
->dhcp_server
, n
,
248 configs
[n
].servers
, configs
[n
].n_servers
);
250 if (!acquired_uplink
) {
251 uplink
= manager_find_uplink(link
->manager
, link
);
252 acquired_uplink
= true;
257 "Not emitting %s on link, couldn't find suitable uplink.",
258 dhcp_lease_info_to_string(n
));
261 r
= link_push_uplink_to_dhcp_server(uplink
, n
, link
->dhcp_server
);
264 log_link_warning_errno(link
, r
,
265 "Failed to set %s for DHCP server, ignoring: %m",
266 dhcp_lease_info_to_string(n
));
269 r
= sd_dhcp_server_set_emit_router(link
->dhcp_server
, link
->network
->dhcp_server_emit_router
);
271 return log_link_error_errno(link
, r
, "Failed to set router emission for DHCP server: %m");
273 if (link
->network
->dhcp_server_emit_timezone
) {
274 _cleanup_free_
char *buffer
= NULL
;
277 if (link
->network
->dhcp_server_timezone
)
278 tz
= link
->network
->dhcp_server_timezone
;
280 r
= get_timezone(&buffer
);
282 return log_link_error_errno(link
, r
, "Failed to determine timezone: %m");
287 r
= sd_dhcp_server_set_timezone(link
->dhcp_server
, tz
);
289 return log_link_error_errno(link
, r
, "Failed to set timezone for DHCP server: %m");
292 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_options
, i
) {
293 r
= sd_dhcp_server_add_option(link
->dhcp_server
, p
);
297 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
300 ORDERED_HASHMAP_FOREACH(p
, link
->network
->dhcp_server_send_vendor_options
, i
) {
301 r
= sd_dhcp_server_add_vendor_option(link
->dhcp_server
, p
);
305 return log_link_error_errno(link
, r
, "Failed to set DHCPv4 option: %m");
308 if (!sd_dhcp_server_is_running(link
->dhcp_server
)) {
309 r
= sd_dhcp_server_start(link
->dhcp_server
);
311 return log_link_error_errno(link
, r
, "Could not start DHCPv4 server instance: %m");
317 static int config_parse_dhcp_lease_server_list(
319 const char *filename
,
323 struct in_addr
**addresses
,
324 unsigned *n_addresses
) {
330 for (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 %s= address '%s', ignoring: %m", lvalue
, w
);
353 struct in_addr
*m
= reallocarray(*addresses
, *n_addresses
+ 1, sizeof(struct in_addr
));
357 m
[(*n_addresses
)++] = a
.in
;
362 int config_parse_dhcp_server_dns(
364 const char *filename
,
367 unsigned section_line
,
376 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
378 &n
->dhcp_server_dns
, &n
->n_dhcp_server_dns
);
381 int config_parse_dhcp_server_ntp(
383 const char *filename
,
386 unsigned section_line
,
395 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
397 &n
->dhcp_server_ntp
, &n
->n_dhcp_server_ntp
);
400 int config_parse_dhcp_server_sip(
402 const char *filename
,
405 unsigned section_line
,
414 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
416 &n
->dhcp_server_sip
, &n
->n_dhcp_server_sip
);
419 int config_parse_dhcp_server_pop3_servers(
421 const char *filename
,
424 unsigned section_line
,
433 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
435 &n
->dhcp_server_pop3
, &n
->n_dhcp_server_pop3
);
438 int config_parse_dhcp_server_smtp_servers(
440 const char *filename
,
443 unsigned section_line
,
452 return config_parse_dhcp_lease_server_list(unit
, filename
, line
,
454 &n
->dhcp_server_smtp
, &n
->n_dhcp_server_smtp
);