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