]> git.ipfire.org Git - network.git/blame - src/networkd/daemon.c
Makefile: Fix typo in localstatedir
[network.git] / src / networkd / daemon.c
CommitLineData
112358f3
MT
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
025f60f1 21#include <errno.h>
5a925d5f 22#include <fcntl.h>
3138451b
MT
23#include <getopt.h>
24#include <limits.h>
112358f3 25#include <stdlib.h>
f6e3fd80 26#include <unistd.h>
112358f3 27
09a6af17 28#include <systemd/sd-bus.h>
8a88982f 29#include <systemd/sd-daemon.h>
b286cd83 30#include <systemd/sd-device.h>
c7e1b5db 31#include <systemd/sd-event.h>
e62b300e 32#include <systemd/sd-netlink.h>
c7e1b5db 33
09a6af17 34#include "bus.h"
2ac78f28 35#include "config.h"
112358f3 36#include "daemon.h"
b286cd83 37#include "devmon.h"
eaf649ee 38#include "link.h"
18b8c841 39#include "links.h"
c251a9dd 40#include "logging.h"
b8db2713 41#include "ports.h"
15240e08 42#include "stats-collector.h"
3138451b 43#include "string.h"
19e74c9b 44#include "zone.h"
0c8e7342 45#include "zones.h"
112358f3 46
b286cd83
MT
47// Increase the receive buffer to 128 MiB
48#define RCVBUF_SIZE 128 * 1024 * 1024
49
112358f3
MT
50struct nw_daemon {
51 int nrefs;
c7e1b5db 52
f6e3fd80 53 // Configuration
25808f65 54 nw_configd* configd;
2361667e 55 nw_config* config;
2ac78f28 56
c7e1b5db
MT
57 // Event Loop
58 sd_event* loop;
09a6af17 59
e62b300e
MT
60 // Netlink Connection
61 sd_netlink* rtnl;
62
09a6af17
MT
63 // DBus Connection
64 sd_bus* bus;
19e74c9b 65
b286cd83
MT
66 // udev Connection
67 sd_device_monitor* devmon;
68
18b8c841 69 // Links
2361667e 70 nw_links* links;
18b8c841 71
19e74c9b 72 // Zones
2361667e 73 nw_zones* zones;
b8db2713
MT
74
75 // Ports
2361667e 76 nw_ports* ports;
b8db2713 77
15240e08
MT
78 // Stats Collector
79 sd_event_source* stats_collector_event;
112358f3
MT
80};
81
27a3a596 82static int __nw_daemon_terminate(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1
MT
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
27a3a596 89static int __nw_daemon_reload(sd_event_source* source, const struct signalfd_siginfo* si,
025f60f1 90 void* data) {
2361667e 91 nw_daemon* daemon = (nw_daemon*)daemon;
27a3a596 92
025f60f1
MT
93 DEBUG("Received signal to reload...\n");
94
27a3a596
MT
95 // Reload the daemon
96 nw_daemon_reload(daemon);
025f60f1
MT
97
98 return 0;
99}
100
5a925d5f
MT
101/*
102 Configuration
103*/
104
105static int nw_daemon_config_open(nw_daemon* daemon, const char* path) {
25808f65 106 int r;
5a925d5f 107
25808f65
MT
108 // Open the configuration directory
109 r = nw_configd_create(&daemon->configd, path);
110 if (r < 0)
111 return r;
8edf3da1 112
25808f65 113 return 0;
8edf3da1
MT
114}
115
3138451b
MT
116static 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:
5a925d5f 135 r = nw_daemon_config_open(daemon, optarg);
3138451b
MT
136 if (r < 0)
137 return r;
3138451b
MT
138 break;
139
140 // Abort on any unrecognised option
141 default:
142 return -EINVAL;
143 }
144 }
145
146 return 0;
147}
148
2361667e 149static int nw_daemon_setup_loop(nw_daemon* daemon) {
c7e1b5db
MT
150 int r;
151
152 // Fetch a reference to the default event loop
153 r = sd_event_default(&daemon->loop);
154 if (r < 0) {
025f60f1 155 ERROR("Could not setup event loop: %s\n", strerror(-r));
c7e1b5db
MT
156 return 1;
157 }
158
3b2316e4
MT
159 // Enable the watchdog
160 r = sd_event_set_watchdog(daemon->loop, 1);
161 if (r < 0) {
025f60f1
MT
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,
27a3a596 168 __nw_daemon_terminate, daemon);
025f60f1
MT
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,
27a3a596 176 __nw_daemon_terminate, daemon);
025f60f1
MT
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,
27a3a596 184 __nw_daemon_reload, daemon);
025f60f1
MT
185 if (r < 0) {
186 ERROR("Could not register handling SIGHUP: %s\n", strerror(-r));
3b2316e4
MT
187 return 1;
188 }
189
c7e1b5db
MT
190 return 0;
191}
192
2361667e 193static int nw_daemon_load_config(nw_daemon* daemon) {
c7e1b5db
MT
194 int r;
195
f6e3fd80 196 // If no configuration path has been opened yet, we will open something
25808f65 197 if (!daemon->configd) {
f6e3fd80
MT
198 r = nw_daemon_config_open(daemon, CONFIG_DIR);
199 if (r < 0)
25808f65 200 return r;
f6e3fd80
MT
201 }
202
5a925d5f 203 // Open the configuration file
25808f65 204 return nw_configd_open_config(&daemon->config, daemon->configd, "settings");
19e74c9b
MT
205}
206
2361667e 207static int nw_start_device_monitor(nw_daemon* daemon) {
b286cd83
MT
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
2361667e 258static int nw_daemon_connect_rtnl(nw_daemon* daemon, int fd) {
e62b300e
MT
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
eaf649ee 283 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_NEWLINK, nw_link_process, NULL,
e62b300e
MT
284 daemon, "networkd-RTM_NEWLINK");
285 if (r < 0) {
286 ERROR("Could not register RTM_NEWLINK: %m\n");
287 return 1;
288 }
289
766f08ca
MT
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
e62b300e
MT
298 return 0;
299}
300
2361667e 301static int nw_daemon_enumerate_links(nw_daemon* daemon) {
18b8c841
MT
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
2361667e 312static int nw_daemon_enumerate_ports(nw_daemon* daemon) {
b8db2713
MT
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
7af642e1
MT
323static 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
2361667e 334static int nw_daemon_enumerate(nw_daemon* daemon) {
18b8c841
MT
335 int r;
336
337 // Links
338 r = nw_daemon_enumerate_links(daemon);
339 if (r)
340 return r;
341
b8db2713
MT
342 // Ports
343 r = nw_daemon_enumerate_ports(daemon);
344 if (r)
345 return r;
346
7af642e1
MT
347 // Zones
348 r = nw_daemon_enumerate_zones(daemon);
349 if (r)
350 return r;
351
18b8c841
MT
352 return 0;
353}
354
b9769b09
MT
355static 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
374static 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
15240e08
MT
386static 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
406ERROR:
407 if (s)
408 sd_event_source_unref(s);
409
410 return r;
411}
412
2361667e 413static int nw_daemon_setup(nw_daemon* daemon) {
19e74c9b
MT
414 int r;
415
416 // Read the configuration
417 r = nw_daemon_load_config(daemon);
418 if (r)
419 return r;
420
c7e1b5db
MT
421 // Setup the event loop
422 r = nw_daemon_setup_loop(daemon);
423 if (r)
424 return r;
425
e62b300e
MT
426 // Connect to the kernel's netlink interface
427 r = nw_daemon_connect_rtnl(daemon, 0);
428 if (r)
429 return r;
430
09a6af17 431 // Connect to the system bus
442b2fc2 432 r = nw_bus_connect(&daemon->bus, daemon->loop, daemon);
09a6af17
MT
433 if (r)
434 return r;
435
b286cd83
MT
436 // Connect to udev
437 r = nw_start_device_monitor(daemon);
438 if (r)
439 return r;
440
18b8c841
MT
441 // Enumerate everything we need to know
442 r = nw_daemon_enumerate(daemon);
443 if (r)
444 return r;
445
b9769b09
MT
446 // (Re-)configure everything
447 r = nw_daemon_reconfigure(daemon);
448 if (r)
449 return r;
450
15240e08
MT
451 // Start the stats collector
452 r = nw_daemon_starts_stats_collector(daemon);
453 if (r)
454 return r;
455
c7e1b5db
MT
456 return 0;
457}
458
3138451b 459int nw_daemon_create(nw_daemon** daemon, int argc, char* argv[]) {
c7e1b5db
MT
460 int r;
461
2361667e 462 nw_daemon* d = calloc(1, sizeof(*d));
112358f3
MT
463 if (!d)
464 return 1;
465
466 // Initialize reference counter
467 d->nrefs = 1;
468
3138451b
MT
469 // Parse command line arguments
470 r = nw_daemon_parse_argv(d, argc, argv);
471 if (r)
472 goto ERROR;
473
c7e1b5db
MT
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
112358f3 482 return 0;
c7e1b5db
MT
483
484ERROR:
485 nw_daemon_unref(d);
486
487 return r;
112358f3
MT
488}
489
2361667e 490static void nw_daemon_cleanup(nw_daemon* daemon) {
b8db2713
MT
491 if (daemon->ports)
492 nw_ports_unref(daemon->ports);
0c8e7342
MT
493 if (daemon->zones)
494 nw_zones_unref(daemon->zones);
18b8c841
MT
495 if (daemon->links)
496 nw_links_unref(daemon->links);
2ac78f28
MT
497 if (daemon->config)
498 nw_config_unref(daemon->config);
18b8c841
MT
499}
500
2361667e 501static void nw_daemon_free(nw_daemon* daemon) {
18b8c841
MT
502 // Cleanup common objects
503 nw_daemon_cleanup(daemon);
504
25808f65
MT
505 if (daemon->configd)
506 nw_configd_unref(daemon->configd);
15240e08
MT
507 if (daemon->stats_collector_event)
508 sd_event_source_unref(daemon->stats_collector_event);
09a6af17
MT
509 if (daemon->bus)
510 sd_bus_unref(daemon->bus);
c7e1b5db
MT
511 if (daemon->loop)
512 sd_event_unref(daemon->loop);
513
112358f3
MT
514 free(daemon);
515}
516
2361667e 517nw_daemon* nw_daemon_ref(nw_daemon* daemon) {
112358f3
MT
518 daemon->nrefs++;
519
520 return daemon;
521}
522
2361667e 523nw_daemon* nw_daemon_unref(nw_daemon* daemon) {
112358f3
MT
524 if (--daemon->nrefs > 0)
525 return daemon;
526
527 nw_daemon_free(daemon);
528 return NULL;
529}
c7e1b5db
MT
530
531/*
532 This function contains the main loop of the daemon...
533*/
2361667e 534int nw_daemon_run(nw_daemon* daemon) {
c7e1b5db
MT
535 int r;
536
8a88982f
MT
537 // We are now ready to process any requests
538 sd_notify(0, "READY=1\n" "STATUS=Processing requests...");
539
c7e1b5db
MT
540 // Launch the event loop
541 r = sd_event_loop(daemon->loop);
8a88982f
MT
542 if (r < 0) {
543 ERROR("Could not run the event loop: %s\n", strerror(-r));
544 goto ERROR;
c7e1b5db
MT
545 }
546
8a88982f
MT
547 // Let systemd know that we are shutting down
548 sd_notify(0, "STOPPING=1\n" "STATUS=Shutting down...");
549
605e975f
MT
550 // Save the configuration
551 r = nw_daemon_save(daemon);
552 if (r)
553 goto ERROR;
554
18b8c841
MT
555 // Cleanup everything
556 nw_daemon_cleanup(daemon);
557
c7e1b5db 558 return 0;
8a88982f
MT
559
560ERROR:
561 sd_notifyf(0, "ERRNO=%i", -r);
562
18b8c841
MT
563 // Cleanup everything
564 nw_daemon_cleanup(daemon);
565
8a88982f 566 return 1;
c7e1b5db 567}
27a3a596 568
2361667e 569int nw_daemon_reload(nw_daemon* daemon) {
27a3a596
MT
570 DEBUG("Reloading daemon...\n");
571
572 // XXX TODO
573
574 return 0;
575}
0c8e7342 576
605e975f
MT
577/*
578 Saves the configuration to disk
579*/
580int nw_daemon_save(nw_daemon* daemon) {
581 int r;
582
583 DEBUG("Saving configuration...\n");
584
8edf3da1 585#if 0
605e975f 586 // Save settings
8edf3da1 587 r = nw_config_write(daemon->config, f);
605e975f
MT
588 if (r)
589 return r;
8edf3da1 590#endif
605e975f
MT
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
25808f65
MT
605nw_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
15240e08
MT
615/*
616 Bus
617*/
618sd_bus* nw_daemon_get_bus(nw_daemon* daemon) {
619 return daemon->bus;
620}
621
eaf649ee
MT
622/*
623 Netlink
624*/
2361667e 625sd_netlink* nw_daemon_get_rtnl(nw_daemon* daemon) {
eaf649ee
MT
626 return daemon->rtnl;
627}
628
766f08ca
MT
629/*
630 Links
631*/
2361667e 632nw_links* nw_daemon_links(nw_daemon* daemon) {
766f08ca
MT
633 return nw_links_ref(daemon->links);
634}
635
2361667e 636void nw_daemon_drop_link(nw_daemon* daemon, nw_link* link) {
766f08ca
MT
637 if (!daemon->links)
638 return;
639
640 nw_links_drop_link(daemon->links, link);
641}
642
2361667e 643nw_link* nw_daemon_get_link_by_ifindex(nw_daemon* daemon, int ifindex) {
766f08ca
MT
644 if (!daemon->links)
645 return NULL;
646
647 return nw_links_get_by_ifindex(daemon->links, ifindex);
648}
649
2361667e 650nw_link* nw_daemon_get_link_by_name(nw_daemon* daemon, const char* name) {
30d4ab67
MT
651 if (!daemon->links)
652 return NULL;
653
654 return nw_links_get_by_name(daemon->links, name);
655}
656
7297ba7f
MT
657/*
658 Ports
659*/
2361667e 660nw_ports* nw_daemon_ports(nw_daemon* daemon) {
7297ba7f
MT
661 return nw_ports_ref(daemon->ports);
662}
663
611d4aca
MT
664int 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
2361667e 671nw_port* nw_daemon_get_port_by_name(nw_daemon* daemon, const char* name) {
7297ba7f
MT
672 if (!daemon->ports)
673 return NULL;
674
675 return nw_ports_get_by_name(daemon->ports, name);
676}
677
bd9ffd6a
MT
678/*
679 Zones
680*/
681
2361667e 682nw_zones* nw_daemon_zones(nw_daemon* daemon) {
0c8e7342
MT
683 return nw_zones_ref(daemon->zones);
684}
bd9ffd6a 685
b4faae0a
MT
686int 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
2361667e 693nw_zone* nw_daemon_get_zone_by_name(nw_daemon* daemon, const char* name) {
bd9ffd6a
MT
694 if (!daemon->zones)
695 return NULL;
696
697 return nw_zones_get_by_name(daemon->zones, name);
698}