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