]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/network/networkd-dhcp-server.c
fix_test_function_timeout
[thirdparty/systemd.git] / src / network / networkd-dhcp-server.c
CommitLineData
8fcf1d61
YW
1/* SPDX-License-Identifier: LGPL-2.1+ */
2
3#include "sd-dhcp-server.h"
4
dd1d3060
MAL
5#include "fd-util.h"
6#include "fileio.h"
8fcf1d61
YW
7#include "networkd-dhcp-server.h"
8#include "networkd-link.h"
9#include "networkd-manager.h"
10#include "networkd-network.h"
564ca984 11#include "parse-util.h"
dd1d3060 12#include "socket-netlink.h"
564ca984
SS
13#include "string-table.h"
14#include "string-util.h"
dd1d3060 15#include "strv.h"
8fcf1d61
YW
16
17static Address* link_find_dhcp_server_address(Link *link) {
18 Address *address;
19
20 assert(link);
21 assert(link->network);
22
23 /* The first statically configured address if there is any */
5dc31db7
ZJS
24 LIST_FOREACH(addresses, address, link->network->static_addresses)
25 if (address->family == AF_INET &&
26 !in_addr_is_null(address->family, &address->in_addr))
27 return address;
8fcf1d61
YW
28
29 /* If that didn't work, find a suitable address we got from the pool */
5dc31db7
ZJS
30 LIST_FOREACH(addresses, address, link->pool_addresses)
31 if (address->family == AF_INET)
32 return address;
8fcf1d61
YW
33
34 return NULL;
35}
36
37static int link_push_uplink_dns_to_dhcp_server(Link *link, sd_dhcp_server *s) {
38 _cleanup_free_ struct in_addr *addresses = NULL;
39 size_t n_addresses = 0, n_allocated = 0;
8fcf1d61 40
5dc31db7 41 for (unsigned i = 0; i < link->network->n_dns; i++) {
8fcf1d61
YW
42 struct in_addr ia;
43
44 /* Only look for IPv4 addresses */
45 if (link->network->dns[i].family != AF_INET)
46 continue;
47
48 ia = link->network->dns[i].address.in;
49
50 /* Never propagate obviously borked data */
51 if (in4_addr_is_null(&ia) || in4_addr_is_localhost(&ia))
52 continue;
53
54 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
55 return log_oom();
56
57 addresses[n_addresses++] = ia;
58 }
59
60 if (link->network->dhcp_use_dns && link->dhcp_lease) {
5dc31db7 61 const struct in_addr *da;
8fcf1d61 62
5dc31db7 63 int n = sd_dhcp_lease_get_dns(link->dhcp_lease, &da);
8fcf1d61 64 if (n > 0) {
8fcf1d61
YW
65 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
66 return log_oom();
67
5dc31db7 68 for (int j = 0; j < n; j++)
8fcf1d61
YW
69 if (in4_addr_is_non_local(&da[j]))
70 addresses[n_addresses++] = da[j];
71 }
72 }
73
74 if (n_addresses <= 0)
75 return 0;
76
77 return sd_dhcp_server_set_dns(s, addresses, n_addresses);
78}
79
24e6f458
ZJS
80static int link_push_uplink_to_dhcp_server(
81 Link *link,
82 sd_dhcp_lease_info what,
83 sd_dhcp_server *s) {
8fcf1d61 84
284e8fd0
SS
85 _cleanup_free_ struct in_addr *addresses = NULL;
86 size_t n_addresses = 0, n_allocated = 0;
24e6f458
ZJS
87 bool lease_condition;
88 char **servers;
284e8fd0
SS
89
90 if (!link->network)
91 return 0;
92
24e6f458 93 log_link_debug(link, "Copying %s from link", dhcp_lease_info_to_string(what));
284e8fd0 94
24e6f458
ZJS
95 switch (what) {
96 case SD_DHCP_LEASE_DNS_SERVERS:
97 /* DNS servers are stored as parsed data, so special handling is required.
98 * TODO: check if DNS servers should be stored unparsed too. */
99 return link_push_uplink_dns_to_dhcp_server(link, s);
284e8fd0 100
24e6f458
ZJS
101 case SD_DHCP_LEASE_NTP_SERVERS:
102 servers = link->network->ntp;
103 lease_condition = link->network->dhcp_use_ntp;
104 break;
284e8fd0 105
24e6f458
ZJS
106 case SD_DHCP_LEASE_POP3_SERVERS:
107 servers = link->network->pop3;
108 lease_condition = true;
109 break;
284e8fd0 110
24e6f458
ZJS
111 case SD_DHCP_LEASE_SMTP_SERVERS:
112 servers = link->network->smtp;
113 lease_condition = true;
114 break;
284e8fd0 115
24e6f458
ZJS
116 case SD_DHCP_LEASE_SIP_SERVERS:
117 servers = link->network->sip;
118 lease_condition = link->network->dhcp_use_sip;
119 break;
284e8fd0 120
d361b373
SS
121 case SD_DHCP_LEASE_LPR_SERVERS:
122 servers = link->network->lpr;
123 lease_condition = true;
124 break;
125
24e6f458 126 default:
86b52a39 127 assert_not_reached("Unknown DHCP lease info item");
284e8fd0
SS
128 }
129
f6269fe7 130 char **a;
24e6f458 131 STRV_FOREACH(a, servers) {
f6269fe7
SS
132 union in_addr_union ia;
133
134 /* Only look for IPv4 addresses */
135 if (in_addr_from_string(AF_INET, *a, &ia) <= 0)
136 continue;
137
138 /* Never propagate obviously borked data */
139 if (in4_addr_is_null(&ia.in) || in4_addr_is_localhost(&ia.in))
140 continue;
141
142 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + 1))
143 return log_oom();
144
145 addresses[n_addresses++] = ia.in;
146 }
147
24e6f458
ZJS
148 if (lease_condition && link->dhcp_lease) {
149 const struct in_addr *da;
f6269fe7 150
a2706075 151 int n = sd_dhcp_lease_get_servers(link->dhcp_lease, what, &da);
f6269fe7 152 if (n > 0) {
f6269fe7
SS
153 if (!GREEDY_REALLOC(addresses, n_allocated, n_addresses + n))
154 return log_oom();
155
a2706075 156 for (int i = 0; i < n; i++)
24e6f458
ZJS
157 if (in4_addr_is_non_local(&da[i]))
158 addresses[n_addresses++] = da[i];
f6269fe7
SS
159 }
160 }
161
162 if (n_addresses <= 0)
163 return 0;
164
24e6f458 165 return sd_dhcp_server_set_servers(s, what, addresses, n_addresses);
299d578f
SS
166}
167
dd1d3060
MAL
168static 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) {
169 for (;;) {
170 _cleanup_free_ char *word = NULL, *server_name = NULL;
171 union in_addr_union address;
172 int family, r, ifindex = 0;
173
174 r = extract_first_word(&string, &word, NULL, 0);
175 if (r < 0)
176 return r;
177 if (r == 0)
178 break;
179
180 r = in_addr_ifindex_name_from_string_auto(word, &family, &address, &ifindex, &server_name);
181 if (r < 0) {
182 log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring: %m", word);
183 continue;
184 }
185
186 /* Only look for IPv4 addresses */
187 if (family != AF_INET)
188 continue;
189
190 /* Never propagate obviously borked data */
191 if (in4_addr_is_null(&address.in) || in4_addr_is_localhost(&address.in))
192 continue;
193
194 if (!GREEDY_REALLOC(*addresses, *n_allocated, *n_addresses + 1))
195 return log_oom();
196
197 (*addresses)[(*n_addresses)++] = address.in;
198 }
199
200 return 0;
201}
202
203static int dhcp4_server_set_dns_from_resolve_conf(Link *link) {
204 _cleanup_free_ struct in_addr *addresses = NULL;
205 size_t n_addresses = 0, n_allocated = 0;
206 _cleanup_fclose_ FILE *f = NULL;
207 int n = 0, r;
208
209 f = fopen(PRIVATE_UPLINK_RESOLV_CONF, "re");
210 if (!f) {
211 if (errno == ENOENT)
212 return 0;
213
214 return log_warning_errno(errno, "Failed to open " PRIVATE_UPLINK_RESOLV_CONF ": %m");
215 }
216
217 for (;;) {
218 _cleanup_free_ char *line = NULL;
219 const char *a;
220 char *l;
221
222 r = read_line(f, LONG_LINE_MAX, &line);
223 if (r < 0)
224 return log_error_errno(r, "Failed to read " PRIVATE_UPLINK_RESOLV_CONF ": %m");
225 if (r == 0)
226 break;
227
228 n++;
229
230 l = strstrip(line);
231 if (IN_SET(*l, '#', ';', 0))
232 continue;
233
234 a = first_word(l, "nameserver");
235 if (!a)
236 continue;
237
238 r = dhcp4_server_parse_dns_server_string_and_warn(link, a, &addresses, &n_allocated, &n_addresses);
239 if (r < 0)
240 log_warning_errno(r, "Failed to parse DNS server address '%s', ignoring.", a);
241 }
242
243 if (n_addresses <= 0)
244 return 0;
245
246 return sd_dhcp_server_set_dns(link->dhcp_server, addresses, n_addresses);
247}
248
8fcf1d61 249int dhcp4_server_configure(Link *link) {
8fcf1d61 250 bool acquired_uplink = false;
461dbb2f 251 sd_dhcp_option *p;
564ca984
SS
252 Link *uplink = NULL;
253 Address *address;
254 Iterator i;
8fcf1d61
YW
255 int r;
256
257 address = link_find_dhcp_server_address(link);
258 if (!address)
c00c3b64
YW
259 return log_link_error_errno(link, SYNTHETIC_ERRNO(EBUSY),
260 "Failed to find suitable address for DHCPv4 server instance.");
8fcf1d61
YW
261
262 /* use the server address' subnet as the pool */
263 r = sd_dhcp_server_configure_pool(link->dhcp_server, &address->in_addr.in, address->prefixlen,
264 link->network->dhcp_server_pool_offset, link->network->dhcp_server_pool_size);
265 if (r < 0)
c00c3b64 266 return log_link_error_errno(link, r, "Failed to configure address pool for DHCPv4 server instance: %m");
8fcf1d61
YW
267
268 /* TODO:
269 r = sd_dhcp_server_set_router(link->dhcp_server, &main_address->in_addr.in);
270 if (r < 0)
271 return r;
272 */
273
274 if (link->network->dhcp_server_max_lease_time_usec > 0) {
275 r = sd_dhcp_server_set_max_lease_time(link->dhcp_server,
276 DIV_ROUND_UP(link->network->dhcp_server_max_lease_time_usec, USEC_PER_SEC));
277 if (r < 0)
c00c3b64 278 return log_link_error_errno(link, r, "Failed to set maximum lease time for DHCPv4 server instance: %m");
8fcf1d61
YW
279 }
280
281 if (link->network->dhcp_server_default_lease_time_usec > 0) {
282 r = sd_dhcp_server_set_default_lease_time(link->dhcp_server,
283 DIV_ROUND_UP(link->network->dhcp_server_default_lease_time_usec, USEC_PER_SEC));
284 if (r < 0)
c00c3b64 285 return log_link_error_errno(link, r, "Failed to set default lease time for DHCPv4 server instance: %m");
8fcf1d61
YW
286 }
287
24e6f458
ZJS
288 const struct {
289 bool condition;
290 const struct in_addr *servers;
291 unsigned n_servers;
292 } configs[] = {
293 [SD_DHCP_LEASE_DNS_SERVERS] = {
294 link->network->dhcp_server_emit_dns,
295 link->network->dhcp_server_dns,
296 link->network->n_dhcp_server_dns,
297 },
298 [SD_DHCP_LEASE_NTP_SERVERS] = {
299 link->network->dhcp_server_emit_ntp,
300 link->network->dhcp_server_ntp,
301 link->network->n_dhcp_server_ntp,
302 },
303 [SD_DHCP_LEASE_SIP_SERVERS] = {
304 link->network->dhcp_server_emit_sip,
305 link->network->dhcp_server_sip,
306 link->network->n_dhcp_server_sip,
307 },
308 [SD_DHCP_LEASE_POP3_SERVERS] = {
309 true,
310 link->network->dhcp_server_pop3,
311 link->network->n_dhcp_server_pop3,
312 },
313 [SD_DHCP_LEASE_SMTP_SERVERS] = {
314 true,
315 link->network->dhcp_server_smtp,
316 link->network->n_dhcp_server_smtp,
317 },
d361b373
SS
318 [SD_DHCP_LEASE_LPR_SERVERS] = {
319 true,
320 link->network->dhcp_server_lpr,
321 link->network->n_dhcp_server_lpr,
322 },
24e6f458
ZJS
323 };
324 assert_cc(ELEMENTSOF(configs) == _SD_DHCP_LEASE_INFO_MAX);
325
326 for (unsigned n = 0; n < ELEMENTSOF(configs); n++)
327 if (configs[n].condition) {
328 if (configs[n].n_servers > 0)
329 r = sd_dhcp_server_set_servers(link->dhcp_server, n,
330 configs[n].servers, configs[n].n_servers);
331 else {
332 if (!acquired_uplink) {
333 uplink = manager_find_uplink(link->manager, link);
334 acquired_uplink = true;
335 }
336
337 if (!uplink) {
338 log_link_debug(link,
339 "Not emitting %s on link, couldn't find suitable uplink.",
340 dhcp_lease_info_to_string(n));
341 r = 0;
dd1d3060 342 } else if (uplink->network)
24e6f458 343 r = link_push_uplink_to_dhcp_server(uplink, n, link->dhcp_server);
dd1d3060
MAL
344 else if (n == SD_DHCP_LEASE_DNS_SERVERS)
345 r = dhcp4_server_set_dns_from_resolve_conf(link);
24e6f458
ZJS
346 }
347 if (r < 0)
348 log_link_warning_errno(link, r,
349 "Failed to set %s for DHCP server, ignoring: %m",
350 dhcp_lease_info_to_string(n));
299d578f 351 }
284e8fd0 352
8fcf1d61
YW
353 r = sd_dhcp_server_set_emit_router(link->dhcp_server, link->network->dhcp_server_emit_router);
354 if (r < 0)
a0fa3ef7 355 return log_link_error_errno(link, r, "Failed to set router emission for DHCP server: %m");
8fcf1d61
YW
356
357 if (link->network->dhcp_server_emit_timezone) {
358 _cleanup_free_ char *buffer = NULL;
359 const char *tz;
360
361 if (link->network->dhcp_server_timezone)
362 tz = link->network->dhcp_server_timezone;
363 else {
364 r = get_timezone(&buffer);
365 if (r < 0)
98b02994 366 return log_link_error_errno(link, r, "Failed to determine timezone: %m");
8fcf1d61
YW
367
368 tz = buffer;
369 }
370
371 r = sd_dhcp_server_set_timezone(link->dhcp_server, tz);
372 if (r < 0)
c00c3b64 373 return log_link_error_errno(link, r, "Failed to set timezone for DHCP server: %m");
8fcf1d61 374 }
564ca984 375
0e96961d 376 ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_options, i) {
461dbb2f 377 r = sd_dhcp_server_add_option(link->dhcp_server, p);
564ca984
SS
378 if (r == -EEXIST)
379 continue;
380 if (r < 0)
c00c3b64 381 return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
564ca984
SS
382 }
383
7354900d
DW
384 ORDERED_HASHMAP_FOREACH(p, link->network->dhcp_server_send_vendor_options, i) {
385 r = sd_dhcp_server_add_vendor_option(link->dhcp_server, p);
386 if (r == -EEXIST)
387 continue;
388 if (r < 0)
389 return log_link_error_errno(link, r, "Failed to set DHCPv4 option: %m");
390 }
391
8fcf1d61
YW
392 if (!sd_dhcp_server_is_running(link->dhcp_server)) {
393 r = sd_dhcp_server_start(link->dhcp_server);
394 if (r < 0)
a0fa3ef7 395 return log_link_error_errno(link, r, "Could not start DHCPv4 server instance: %m");
8fcf1d61
YW
396 }
397
398 return 0;
399}
400
c1997a5b 401static int config_parse_dhcp_lease_server_list(
8fcf1d61
YW
402 const char *unit,
403 const char *filename,
404 unsigned line,
8fcf1d61 405 const char *lvalue,
8fcf1d61 406 const char *rvalue,
c1997a5b
ZJS
407 struct in_addr **addresses,
408 unsigned *n_addresses) {
8fcf1d61
YW
409
410 assert(filename);
411 assert(lvalue);
412 assert(rvalue);
413
c1997a5b 414 for (const char *p = rvalue;;) {
8fcf1d61
YW
415 _cleanup_free_ char *w = NULL;
416 union in_addr_union a;
c1997a5b 417 int r;
8fcf1d61
YW
418
419 r = extract_first_word(&p, &w, NULL, 0);
420 if (r == -ENOMEM)
421 return log_oom();
422 if (r < 0) {
423 log_syntax(unit, LOG_ERR, filename, line, r,
424 "Failed to extract word, ignoring: %s", rvalue);
425 return 0;
426 }
427 if (r == 0)
c1997a5b 428 return 0;
8fcf1d61
YW
429
430 r = in_addr_from_string(AF_INET, w, &a);
431 if (r < 0) {
432 log_syntax(unit, LOG_ERR, filename, line, r,
c1997a5b 433 "Failed to parse %s= address '%s', ignoring: %m", lvalue, w);
8fcf1d61
YW
434 continue;
435 }
436
c1997a5b 437 struct in_addr *m = reallocarray(*addresses, *n_addresses + 1, sizeof(struct in_addr));
8fcf1d61
YW
438 if (!m)
439 return log_oom();
440
c1997a5b
ZJS
441 m[(*n_addresses)++] = a.in;
442 *addresses = m;
8fcf1d61 443 }
8fcf1d61
YW
444}
445
c1997a5b 446int config_parse_dhcp_server_dns(
8fcf1d61
YW
447 const char *unit,
448 const char *filename,
449 unsigned line,
450 const char *section,
451 unsigned section_line,
452 const char *lvalue,
453 int ltype,
454 const char *rvalue,
455 void *data,
456 void *userdata) {
457
458 Network *n = data;
8fcf1d61 459
c1997a5b
ZJS
460 return config_parse_dhcp_lease_server_list(unit, filename, line,
461 lvalue, rvalue,
462 &n->dhcp_server_dns, &n->n_dhcp_server_dns);
463}
8fcf1d61 464
c1997a5b
ZJS
465int config_parse_dhcp_server_ntp(
466 const char *unit,
467 const char *filename,
468 unsigned line,
469 const char *section,
470 unsigned section_line,
471 const char *lvalue,
472 int ltype,
473 const char *rvalue,
474 void *data,
475 void *userdata) {
8fcf1d61 476
c1997a5b 477 Network *n = data;
8fcf1d61 478
c1997a5b
ZJS
479 return config_parse_dhcp_lease_server_list(unit, filename, line,
480 lvalue, rvalue,
481 &n->dhcp_server_ntp, &n->n_dhcp_server_ntp);
8fcf1d61 482}
299d578f
SS
483
484int config_parse_dhcp_server_sip(
485 const char *unit,
486 const char *filename,
487 unsigned line,
488 const char *section,
489 unsigned section_line,
490 const char *lvalue,
491 int ltype,
492 const char *rvalue,
493 void *data,
494 void *userdata) {
495
496 Network *n = data;
299d578f 497
c1997a5b
ZJS
498 return config_parse_dhcp_lease_server_list(unit, filename, line,
499 lvalue, rvalue,
500 &n->dhcp_server_sip, &n->n_dhcp_server_sip);
299d578f 501}
284e8fd0
SS
502
503int config_parse_dhcp_server_pop3_servers(
504 const char *unit,
505 const char *filename,
506 unsigned line,
507 const char *section,
508 unsigned section_line,
509 const char *lvalue,
510 int ltype,
511 const char *rvalue,
512 void *data,
513 void *userdata) {
514
515 Network *n = data;
284e8fd0 516
c1997a5b
ZJS
517 return config_parse_dhcp_lease_server_list(unit, filename, line,
518 lvalue, rvalue,
519 &n->dhcp_server_pop3, &n->n_dhcp_server_pop3);
f6269fe7
SS
520}
521
522int config_parse_dhcp_server_smtp_servers(
523 const char *unit,
524 const char *filename,
525 unsigned line,
526 const char *section,
527 unsigned section_line,
528 const char *lvalue,
529 int ltype,
530 const char *rvalue,
531 void *data,
532 void *userdata) {
533
534 Network *n = data;
f6269fe7 535
c1997a5b
ZJS
536 return config_parse_dhcp_lease_server_list(unit, filename, line,
537 lvalue, rvalue,
538 &n->dhcp_server_smtp, &n->n_dhcp_server_smtp);
f6269fe7 539
284e8fd0 540}
d361b373
SS
541
542int config_parse_dhcp_server_lpr_servers(
543 const char *unit,
544 const char *filename,
545 unsigned line,
546 const char *section,
547 unsigned section_line,
548 const char *lvalue,
549 int ltype,
550 const char *rvalue,
551 void *data,
552 void *userdata) {
553
554 Network *n = data;
555
556 return config_parse_dhcp_lease_server_list(unit, filename, line,
557 lvalue, rvalue,
558 &n->dhcp_server_lpr, &n->n_dhcp_server_lpr);
559
560}