]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/daemon.c
Makefile: Fix typo in localstatedir
[people/ms/network.git] / src / networkd / daemon.c
1 /*#############################################################################
2 # #
3 # IPFire.org - A linux based firewall #
4 # Copyright (C) 2023 IPFire Network Development Team #
5 # #
6 # This program is free software: you can redistribute it and/or modify #
7 # it under the terms of the GNU General Public License as published by #
8 # the Free Software Foundation, either version 3 of the License, or #
9 # (at your option) any later version. #
10 # #
11 # This program is distributed in the hope that it will be useful, #
12 # but WITHOUT ANY WARRANTY; without even the implied warranty of #
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
14 # GNU General Public License for more details. #
15 # #
16 # You should have received a copy of the GNU General Public License #
17 # along with this program. If not, see <http://www.gnu.org/licenses/>. #
18 # #
19 #############################################################################*/
20
21 #include <errno.h>
22 #include <fcntl.h>
23 #include <getopt.h>
24 #include <limits.h>
25 #include <stdlib.h>
26 #include <unistd.h>
27
28 #include <systemd/sd-bus.h>
29 #include <systemd/sd-daemon.h>
30 #include <systemd/sd-device.h>
31 #include <systemd/sd-event.h>
32 #include <systemd/sd-netlink.h>
33
34 #include "bus.h"
35 #include "config.h"
36 #include "daemon.h"
37 #include "devmon.h"
38 #include "link.h"
39 #include "links.h"
40 #include "logging.h"
41 #include "ports.h"
42 #include "stats-collector.h"
43 #include "string.h"
44 #include "zone.h"
45 #include "zones.h"
46
47 // Increase the receive buffer to 128 MiB
48 #define RCVBUF_SIZE 128 * 1024 * 1024
49
50 struct nw_daemon {
51 int nrefs;
52
53 // Configuration
54 nw_configd* configd;
55 nw_config* config;
56
57 // Event Loop
58 sd_event* loop;
59
60 // Netlink Connection
61 sd_netlink* rtnl;
62
63 // DBus Connection
64 sd_bus* bus;
65
66 // udev Connection
67 sd_device_monitor* devmon;
68
69 // Links
70 nw_links* links;
71
72 // Zones
73 nw_zones* zones;
74
75 // Ports
76 nw_ports* ports;
77
78 // Stats Collector
79 sd_event_source* stats_collector_event;
80 };
81
82 static int __nw_daemon_terminate(sd_event_source* source, const struct signalfd_siginfo* si,
83 void* data) {
84 DEBUG("Received signal to terminate...\n");
85
86 return sd_event_exit(sd_event_source_get_event(source), 0);
87 }
88
89 static int __nw_daemon_reload(sd_event_source* source, const struct signalfd_siginfo* si,
90 void* data) {
91 nw_daemon* daemon = (nw_daemon*)daemon;
92
93 DEBUG("Received signal to reload...\n");
94
95 // Reload the daemon
96 nw_daemon_reload(daemon);
97
98 return 0;
99 }
100
101 /*
102 Configuration
103 */
104
105 static int nw_daemon_config_open(nw_daemon* daemon, const char* path) {
106 int r;
107
108 // Open the configuration directory
109 r = nw_configd_create(&daemon->configd, path);
110 if (r < 0)
111 return r;
112
113 return 0;
114 }
115
116 static int nw_daemon_parse_argv(nw_daemon* daemon, int argc, char* argv[]) {
117 enum {
118 ARG_CONFIG,
119 };
120 int r;
121
122 static const struct option options[] = {
123 { "config", required_argument, NULL, ARG_CONFIG },
124 { NULL },
125 };
126 int c;
127
128 for (;;) {
129 c = getopt_long(argc, argv, "", options, NULL);
130 if (c < 0)
131 break;
132
133 switch (c) {
134 case ARG_CONFIG:
135 r = nw_daemon_config_open(daemon, optarg);
136 if (r < 0)
137 return r;
138 break;
139
140 // Abort on any unrecognised option
141 default:
142 return -EINVAL;
143 }
144 }
145
146 return 0;
147 }
148
149 static int nw_daemon_setup_loop(nw_daemon* daemon) {
150 int r;
151
152 // Fetch a reference to the default event loop
153 r = sd_event_default(&daemon->loop);
154 if (r < 0) {
155 ERROR("Could not setup event loop: %s\n", strerror(-r));
156 return 1;
157 }
158
159 // Enable the watchdog
160 r = sd_event_set_watchdog(daemon->loop, 1);
161 if (r < 0) {
162 ERROR("Could not activate watchdog: %s\n", strerror(-r));
163 return 1;
164 }
165
166 // Listen for SIGTERM
167 r = sd_event_add_signal(daemon->loop, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK,
168 __nw_daemon_terminate, daemon);
169 if (r < 0) {
170 ERROR("Could not register handling SIGTERM: %s\n", strerror(-r));
171 return 1;
172 }
173
174 // Listen for SIGINT
175 r = sd_event_add_signal(daemon->loop, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK,
176 __nw_daemon_terminate, daemon);
177 if (r < 0) {
178 ERROR("Could not register handling SIGINT: %s\n", strerror(-r));
179 return 1;
180 }
181
182 // Listen for SIGHUP
183 r = sd_event_add_signal(daemon->loop, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK,
184 __nw_daemon_reload, daemon);
185 if (r < 0) {
186 ERROR("Could not register handling SIGHUP: %s\n", strerror(-r));
187 return 1;
188 }
189
190 return 0;
191 }
192
193 static int nw_daemon_load_config(nw_daemon* daemon) {
194 int r;
195
196 // If no configuration path has been opened yet, we will open something
197 if (!daemon->configd) {
198 r = nw_daemon_config_open(daemon, CONFIG_DIR);
199 if (r < 0)
200 return r;
201 }
202
203 // Open the configuration file
204 return nw_configd_open_config(&daemon->config, daemon->configd, "settings");
205 }
206
207 static int nw_start_device_monitor(nw_daemon* daemon) {
208 int r;
209
210 const char* subsystems[] = {
211 "net",
212 "ieee80211",
213 "rfkill",
214 NULL,
215 };
216
217 // Create a new connection to monitor any devices
218 r = sd_device_monitor_new(&daemon->devmon);
219 if (r < 0) {
220 ERROR("Could not inititalize the device monitor: %m\n");
221 return 1;
222 }
223
224 // Increase the receive buffer
225 r = sd_device_monitor_set_receive_buffer_size(daemon->devmon, RCVBUF_SIZE);
226 if (r < 0) {
227 ERROR("Could not increase buffer size for the device monitor: %m\n");
228 return 1;
229 }
230
231 // Filter for events for all relevant subsystems
232 for (const char** subsystem = subsystems; *subsystem; subsystem++) {
233 r = sd_device_monitor_filter_add_match_subsystem_devtype(
234 daemon->devmon, *subsystem, NULL);
235 if (r < 1) {
236 ERROR("Could not add device monitor for the %s subsystem: %m\n", *subsystem);
237 return 1;
238 }
239 }
240
241 // Attach the device monitor to the event loop
242 r = sd_device_monitor_attach_event(daemon->devmon, daemon->loop);
243 if (r < 0) {
244 ERROR("Could not attach the device monitor to the event loop: %m\n");
245 return 1;
246 }
247
248 // Start processing events...
249 r = sd_device_monitor_start(daemon->devmon, nw_devmon_handle_uevent, daemon);
250 if (r < 0) {
251 ERROR("Could not start the device monitor: %m\n");
252 return 1;
253 }
254
255 return 0;
256 }
257
258 static int nw_daemon_connect_rtnl(nw_daemon* daemon, int fd) {
259 int r;
260
261 // Connect to Netlink
262 r = sd_netlink_open(&daemon->rtnl);
263 if (r < 0) {
264 ERROR("Could not connect to the kernel's netlink interface: %m\n");
265 return 1;
266 }
267
268 // Increase the receive buffer
269 r = sd_netlink_increase_rxbuf(daemon->rtnl, RCVBUF_SIZE);
270 if (r < 0) {
271 ERROR("Could not increase receive buffer for the netlink socket: %m\n");
272 return 1;
273 }
274
275 // Connect it to the event loop
276 r = sd_netlink_attach_event(daemon->rtnl, daemon->loop, 0);
277 if (r < 0) {
278 ERROR("Could not connect the netlink socket to the event loop: %m\n");
279 return 1;
280 }
281
282 // Register callback for new interfaces
283 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_NEWLINK, nw_link_process, NULL,
284 daemon, "networkd-RTM_NEWLINK");
285 if (r < 0) {
286 ERROR("Could not register RTM_NEWLINK: %m\n");
287 return 1;
288 }
289
290 // Register callback for deleted interfaces
291 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_DELLINK, nw_link_process, NULL,
292 daemon, "networkd-RTM_DELLINK");
293 if (r < 0) {
294 ERROR("Could not register RTM_DELLINK: %m\n");
295 return 1;
296 }
297
298 return 0;
299 }
300
301 static int nw_daemon_enumerate_links(nw_daemon* daemon) {
302 int r;
303
304 // Create a new links container
305 r = nw_links_create(&daemon->links, daemon);
306 if (r)
307 return r;
308
309 return nw_links_enumerate(daemon->links);
310 }
311
312 static int nw_daemon_enumerate_ports(nw_daemon* daemon) {
313 int r;
314
315 // Create a new ports container
316 r = nw_ports_create(&daemon->ports, daemon);
317 if (r)
318 return r;
319
320 return nw_ports_enumerate(daemon->ports);
321 }
322
323 static int nw_daemon_enumerate_zones(nw_daemon* daemon) {
324 int r;
325
326 // Create a new zones container
327 r = nw_zones_create(&daemon->zones, daemon);
328 if (r)
329 return r;
330
331 return nw_zones_enumerate(daemon->zones);
332 }
333
334 static int nw_daemon_enumerate(nw_daemon* daemon) {
335 int r;
336
337 // Links
338 r = nw_daemon_enumerate_links(daemon);
339 if (r)
340 return r;
341
342 // Ports
343 r = nw_daemon_enumerate_ports(daemon);
344 if (r)
345 return r;
346
347 // Zones
348 r = nw_daemon_enumerate_zones(daemon);
349 if (r)
350 return r;
351
352 return 0;
353 }
354
355 static int __nw_daemon_reconfigure(sd_event_source* s, void* data) {
356 nw_daemon* daemon = (nw_daemon*)data;
357 int r;
358
359 DEBUG("Reconfiguring...\n");
360
361 // Reconfigure all zones
362 r = nw_zones_reconfigure(daemon->zones);
363 if (r)
364 return r;
365
366 // Reconfigure all ports
367 r = nw_ports_reconfigure(daemon->ports);
368 if (r)
369 return r;
370
371 return 0;
372 }
373
374 static int nw_daemon_reconfigure(nw_daemon* daemon) {
375 int r;
376
377 r = sd_event_add_defer(daemon->loop, NULL, __nw_daemon_reconfigure, daemon);
378 if (r) {
379 ERROR("Could not schedule re-configuration task: %m\n");
380 return r;
381 }
382
383 return 0;
384 }
385
386 static int nw_daemon_starts_stats_collector(nw_daemon* daemon) {
387 sd_event_source* s = NULL;
388 int r;
389
390 // Register the stats collector main function
391 r = sd_event_add_time_relative(daemon->loop, &s, CLOCK_MONOTONIC, 0, 0,
392 nw_stats_collector, daemon);
393 if (r < 0) {
394 ERROR("Could not start the stats collector: %m\n");
395 goto ERROR;
396 }
397
398 // Keep calling the stats collector for forever
399 r = sd_event_source_set_enabled(s, SD_EVENT_ON);
400 if (r < 0)
401 goto ERROR;
402
403 // Keep a reference to the event source
404 daemon->stats_collector_event = sd_event_source_ref(s);
405
406 ERROR:
407 if (s)
408 sd_event_source_unref(s);
409
410 return r;
411 }
412
413 static int nw_daemon_setup(nw_daemon* daemon) {
414 int r;
415
416 // Read the configuration
417 r = nw_daemon_load_config(daemon);
418 if (r)
419 return r;
420
421 // Setup the event loop
422 r = nw_daemon_setup_loop(daemon);
423 if (r)
424 return r;
425
426 // Connect to the kernel's netlink interface
427 r = nw_daemon_connect_rtnl(daemon, 0);
428 if (r)
429 return r;
430
431 // Connect to the system bus
432 r = nw_bus_connect(&daemon->bus, daemon->loop, daemon);
433 if (r)
434 return r;
435
436 // Connect to udev
437 r = nw_start_device_monitor(daemon);
438 if (r)
439 return r;
440
441 // Enumerate everything we need to know
442 r = nw_daemon_enumerate(daemon);
443 if (r)
444 return r;
445
446 // (Re-)configure everything
447 r = nw_daemon_reconfigure(daemon);
448 if (r)
449 return r;
450
451 // Start the stats collector
452 r = nw_daemon_starts_stats_collector(daemon);
453 if (r)
454 return r;
455
456 return 0;
457 }
458
459 int nw_daemon_create(nw_daemon** daemon, int argc, char* argv[]) {
460 int r;
461
462 nw_daemon* d = calloc(1, sizeof(*d));
463 if (!d)
464 return 1;
465
466 // Initialize reference counter
467 d->nrefs = 1;
468
469 // Parse command line arguments
470 r = nw_daemon_parse_argv(d, argc, argv);
471 if (r)
472 goto ERROR;
473
474 // Setup the daemon
475 r = nw_daemon_setup(d);
476 if (r)
477 goto ERROR;
478
479 // Set the reference
480 *daemon = d;
481
482 return 0;
483
484 ERROR:
485 nw_daemon_unref(d);
486
487 return r;
488 }
489
490 static void nw_daemon_cleanup(nw_daemon* daemon) {
491 if (daemon->ports)
492 nw_ports_unref(daemon->ports);
493 if (daemon->zones)
494 nw_zones_unref(daemon->zones);
495 if (daemon->links)
496 nw_links_unref(daemon->links);
497 if (daemon->config)
498 nw_config_unref(daemon->config);
499 }
500
501 static void nw_daemon_free(nw_daemon* daemon) {
502 // Cleanup common objects
503 nw_daemon_cleanup(daemon);
504
505 if (daemon->configd)
506 nw_configd_unref(daemon->configd);
507 if (daemon->stats_collector_event)
508 sd_event_source_unref(daemon->stats_collector_event);
509 if (daemon->bus)
510 sd_bus_unref(daemon->bus);
511 if (daemon->loop)
512 sd_event_unref(daemon->loop);
513
514 free(daemon);
515 }
516
517 nw_daemon* nw_daemon_ref(nw_daemon* daemon) {
518 daemon->nrefs++;
519
520 return daemon;
521 }
522
523 nw_daemon* nw_daemon_unref(nw_daemon* daemon) {
524 if (--daemon->nrefs > 0)
525 return daemon;
526
527 nw_daemon_free(daemon);
528 return NULL;
529 }
530
531 /*
532 This function contains the main loop of the daemon...
533 */
534 int nw_daemon_run(nw_daemon* daemon) {
535 int r;
536
537 // We are now ready to process any requests
538 sd_notify(0, "READY=1\n" "STATUS=Processing requests...");
539
540 // Launch the event loop
541 r = sd_event_loop(daemon->loop);
542 if (r < 0) {
543 ERROR("Could not run the event loop: %s\n", strerror(-r));
544 goto ERROR;
545 }
546
547 // Let systemd know that we are shutting down
548 sd_notify(0, "STOPPING=1\n" "STATUS=Shutting down...");
549
550 // Save the configuration
551 r = nw_daemon_save(daemon);
552 if (r)
553 goto ERROR;
554
555 // Cleanup everything
556 nw_daemon_cleanup(daemon);
557
558 return 0;
559
560 ERROR:
561 sd_notifyf(0, "ERRNO=%i", -r);
562
563 // Cleanup everything
564 nw_daemon_cleanup(daemon);
565
566 return 1;
567 }
568
569 int nw_daemon_reload(nw_daemon* daemon) {
570 DEBUG("Reloading daemon...\n");
571
572 // XXX TODO
573
574 return 0;
575 }
576
577 /*
578 Saves the configuration to disk
579 */
580 int nw_daemon_save(nw_daemon* daemon) {
581 int r;
582
583 DEBUG("Saving configuration...\n");
584
585 #if 0
586 // Save settings
587 r = nw_config_write(daemon->config, f);
588 if (r)
589 return r;
590 #endif
591
592 // Save ports
593 r = nw_ports_save(daemon->ports);
594 if (r)
595 return r;
596
597 // Save zones
598 r = nw_zones_save(daemon->zones);
599 if (r)
600 return r;
601
602 return 0;
603 }
604
605 nw_configd* nw_daemon_configd(nw_daemon* daemon, const char* path) {
606 if (!daemon->configd)
607 return NULL;
608
609 if (path)
610 return nw_configd_descend(daemon->configd, path);
611
612 return nw_configd_ref(daemon->configd);
613 }
614
615 /*
616 Bus
617 */
618 sd_bus* nw_daemon_get_bus(nw_daemon* daemon) {
619 return daemon->bus;
620 }
621
622 /*
623 Netlink
624 */
625 sd_netlink* nw_daemon_get_rtnl(nw_daemon* daemon) {
626 return daemon->rtnl;
627 }
628
629 /*
630 Links
631 */
632 nw_links* nw_daemon_links(nw_daemon* daemon) {
633 return nw_links_ref(daemon->links);
634 }
635
636 void nw_daemon_drop_link(nw_daemon* daemon, nw_link* link) {
637 if (!daemon->links)
638 return;
639
640 nw_links_drop_link(daemon->links, link);
641 }
642
643 nw_link* nw_daemon_get_link_by_ifindex(nw_daemon* daemon, int ifindex) {
644 if (!daemon->links)
645 return NULL;
646
647 return nw_links_get_by_ifindex(daemon->links, ifindex);
648 }
649
650 nw_link* nw_daemon_get_link_by_name(nw_daemon* daemon, const char* name) {
651 if (!daemon->links)
652 return NULL;
653
654 return nw_links_get_by_name(daemon->links, name);
655 }
656
657 /*
658 Ports
659 */
660 nw_ports* nw_daemon_ports(nw_daemon* daemon) {
661 return nw_ports_ref(daemon->ports);
662 }
663
664 int nw_daemon_ports_walk(nw_daemon* daemon, nw_ports_walk_callback callback, void* data) {
665 if (!daemon->ports)
666 return 0;
667
668 return nw_ports_walk(daemon->ports, callback, data);
669 }
670
671 nw_port* nw_daemon_get_port_by_name(nw_daemon* daemon, const char* name) {
672 if (!daemon->ports)
673 return NULL;
674
675 return nw_ports_get_by_name(daemon->ports, name);
676 }
677
678 /*
679 Zones
680 */
681
682 nw_zones* nw_daemon_zones(nw_daemon* daemon) {
683 return nw_zones_ref(daemon->zones);
684 }
685
686 int nw_daemon_zones_walk(nw_daemon* daemon, nw_zones_walk_callback callback, void* data) {
687 if (!daemon->zones)
688 return 0;
689
690 return nw_zones_walk(daemon->zones, callback, data);
691 }
692
693 nw_zone* nw_daemon_get_zone_by_name(nw_daemon* daemon, const char* name) {
694 if (!daemon->zones)
695 return NULL;
696
697 return nw_zones_get_by_name(daemon->zones, name);
698 }