]> git.ipfire.org Git - people/ms/network.git/blob - src/networkd/daemon.c
networkd: Save configuration when the daemon exits
[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 <stdlib.h>
23
24 #include <systemd/sd-bus.h>
25 #include <systemd/sd-daemon.h>
26 #include <systemd/sd-device.h>
27 #include <systemd/sd-event.h>
28 #include <systemd/sd-netlink.h>
29
30 #include "bus.h"
31 #include "config.h"
32 #include "daemon.h"
33 #include "devmon.h"
34 #include "link.h"
35 #include "links.h"
36 #include "logging.h"
37 #include "ports.h"
38 #include "zone.h"
39 #include "zones.h"
40
41 // Increase the receive buffer to 128 MiB
42 #define RCVBUF_SIZE 128 * 1024 * 1024
43
44 struct nw_daemon {
45 int nrefs;
46
47 nw_config* config;
48
49 // Event Loop
50 sd_event* loop;
51
52 // Netlink Connection
53 sd_netlink* rtnl;
54
55 // DBus Connection
56 sd_bus* bus;
57
58 // udev Connection
59 sd_device_monitor* devmon;
60
61 // Links
62 nw_links* links;
63
64 // Zones
65 nw_zones* zones;
66
67 // Ports
68 nw_ports* ports;
69
70 };
71
72 static int __nw_daemon_terminate(sd_event_source* source, const struct signalfd_siginfo* si,
73 void* data) {
74 DEBUG("Received signal to terminate...\n");
75
76 return sd_event_exit(sd_event_source_get_event(source), 0);
77 }
78
79 static int __nw_daemon_reload(sd_event_source* source, const struct signalfd_siginfo* si,
80 void* data) {
81 nw_daemon* daemon = (nw_daemon*)daemon;
82
83 DEBUG("Received signal to reload...\n");
84
85 // Reload the daemon
86 nw_daemon_reload(daemon);
87
88 return 0;
89 }
90
91 static int nw_daemon_setup_loop(nw_daemon* daemon) {
92 int r;
93
94 // Fetch a reference to the default event loop
95 r = sd_event_default(&daemon->loop);
96 if (r < 0) {
97 ERROR("Could not setup event loop: %s\n", strerror(-r));
98 return 1;
99 }
100
101 // Enable the watchdog
102 r = sd_event_set_watchdog(daemon->loop, 1);
103 if (r < 0) {
104 ERROR("Could not activate watchdog: %s\n", strerror(-r));
105 return 1;
106 }
107
108 // Listen for SIGTERM
109 r = sd_event_add_signal(daemon->loop, NULL, SIGTERM|SD_EVENT_SIGNAL_PROCMASK,
110 __nw_daemon_terminate, daemon);
111 if (r < 0) {
112 ERROR("Could not register handling SIGTERM: %s\n", strerror(-r));
113 return 1;
114 }
115
116 // Listen for SIGINT
117 r = sd_event_add_signal(daemon->loop, NULL, SIGINT|SD_EVENT_SIGNAL_PROCMASK,
118 __nw_daemon_terminate, daemon);
119 if (r < 0) {
120 ERROR("Could not register handling SIGINT: %s\n", strerror(-r));
121 return 1;
122 }
123
124 // Listen for SIGHUP
125 r = sd_event_add_signal(daemon->loop, NULL, SIGHUP|SD_EVENT_SIGNAL_PROCMASK,
126 __nw_daemon_reload, daemon);
127 if (r < 0) {
128 ERROR("Could not register handling SIGHUP: %s\n", strerror(-r));
129 return 1;
130 }
131
132 return 0;
133 }
134
135 static int nw_daemon_load_config(nw_daemon* daemon) {
136 int r;
137
138 // Read configuration file
139 r = nw_config_create(&daemon->config, CONFIG_DIR "/settings");
140 if (r)
141 return r;
142
143 return r;
144 }
145
146 static int nw_start_device_monitor(nw_daemon* daemon) {
147 int r;
148
149 const char* subsystems[] = {
150 "net",
151 "ieee80211",
152 "rfkill",
153 NULL,
154 };
155
156 // Create a new connection to monitor any devices
157 r = sd_device_monitor_new(&daemon->devmon);
158 if (r < 0) {
159 ERROR("Could not inititalize the device monitor: %m\n");
160 return 1;
161 }
162
163 // Increase the receive buffer
164 r = sd_device_monitor_set_receive_buffer_size(daemon->devmon, RCVBUF_SIZE);
165 if (r < 0) {
166 ERROR("Could not increase buffer size for the device monitor: %m\n");
167 return 1;
168 }
169
170 // Filter for events for all relevant subsystems
171 for (const char** subsystem = subsystems; *subsystem; subsystem++) {
172 r = sd_device_monitor_filter_add_match_subsystem_devtype(
173 daemon->devmon, *subsystem, NULL);
174 if (r < 1) {
175 ERROR("Could not add device monitor for the %s subsystem: %m\n", *subsystem);
176 return 1;
177 }
178 }
179
180 // Attach the device monitor to the event loop
181 r = sd_device_monitor_attach_event(daemon->devmon, daemon->loop);
182 if (r < 0) {
183 ERROR("Could not attach the device monitor to the event loop: %m\n");
184 return 1;
185 }
186
187 // Start processing events...
188 r = sd_device_monitor_start(daemon->devmon, nw_devmon_handle_uevent, daemon);
189 if (r < 0) {
190 ERROR("Could not start the device monitor: %m\n");
191 return 1;
192 }
193
194 return 0;
195 }
196
197 static int nw_daemon_connect_rtnl(nw_daemon* daemon, int fd) {
198 int r;
199
200 // Connect to Netlink
201 r = sd_netlink_open(&daemon->rtnl);
202 if (r < 0) {
203 ERROR("Could not connect to the kernel's netlink interface: %m\n");
204 return 1;
205 }
206
207 // Increase the receive buffer
208 r = sd_netlink_increase_rxbuf(daemon->rtnl, RCVBUF_SIZE);
209 if (r < 0) {
210 ERROR("Could not increase receive buffer for the netlink socket: %m\n");
211 return 1;
212 }
213
214 // Connect it to the event loop
215 r = sd_netlink_attach_event(daemon->rtnl, daemon->loop, 0);
216 if (r < 0) {
217 ERROR("Could not connect the netlink socket to the event loop: %m\n");
218 return 1;
219 }
220
221 // Register callback for new interfaces
222 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_NEWLINK, nw_link_process, NULL,
223 daemon, "networkd-RTM_NEWLINK");
224 if (r < 0) {
225 ERROR("Could not register RTM_NEWLINK: %m\n");
226 return 1;
227 }
228
229 // Register callback for deleted interfaces
230 r = sd_netlink_add_match(daemon->rtnl, NULL, RTM_DELLINK, nw_link_process, NULL,
231 daemon, "networkd-RTM_DELLINK");
232 if (r < 0) {
233 ERROR("Could not register RTM_DELLINK: %m\n");
234 return 1;
235 }
236
237 return 0;
238 }
239
240 static int nw_daemon_enumerate_links(nw_daemon* daemon) {
241 int r;
242
243 // Create a new links container
244 r = nw_links_create(&daemon->links, daemon);
245 if (r)
246 return r;
247
248 return nw_links_enumerate(daemon->links);
249 }
250
251 static int nw_daemon_enumerate_ports(nw_daemon* daemon) {
252 int r;
253
254 // Create a new ports container
255 r = nw_ports_create(&daemon->ports, daemon);
256 if (r)
257 return r;
258
259 return nw_ports_enumerate(daemon->ports);
260 }
261
262 static int nw_daemon_enumerate_zones(nw_daemon* daemon) {
263 int r;
264
265 // Create a new zones container
266 r = nw_zones_create(&daemon->zones, daemon);
267 if (r)
268 return r;
269
270 return nw_zones_enumerate(daemon->zones);
271 }
272
273 static int nw_daemon_enumerate(nw_daemon* daemon) {
274 int r;
275
276 // Links
277 r = nw_daemon_enumerate_links(daemon);
278 if (r)
279 return r;
280
281 // Ports
282 r = nw_daemon_enumerate_ports(daemon);
283 if (r)
284 return r;
285
286 // Zones
287 r = nw_daemon_enumerate_zones(daemon);
288 if (r)
289 return r;
290
291 return 0;
292 }
293
294 static int nw_daemon_setup(nw_daemon* daemon) {
295 int r;
296
297 // Read the configuration
298 r = nw_daemon_load_config(daemon);
299 if (r)
300 return r;
301
302 // Setup the event loop
303 r = nw_daemon_setup_loop(daemon);
304 if (r)
305 return r;
306
307 // Connect to the kernel's netlink interface
308 r = nw_daemon_connect_rtnl(daemon, 0);
309 if (r)
310 return r;
311
312 // Connect to the system bus
313 r = nw_bus_connect(daemon->bus, daemon->loop, daemon);
314 if (r)
315 return r;
316
317 // Connect to udev
318 r = nw_start_device_monitor(daemon);
319 if (r)
320 return r;
321
322 // Enumerate everything we need to know
323 r = nw_daemon_enumerate(daemon);
324 if (r)
325 return r;
326
327 return 0;
328 }
329
330 int nw_daemon_create(nw_daemon** daemon) {
331 int r;
332
333 nw_daemon* d = calloc(1, sizeof(*d));
334 if (!d)
335 return 1;
336
337 // Initialize reference counter
338 d->nrefs = 1;
339
340 // Setup the daemon
341 r = nw_daemon_setup(d);
342 if (r)
343 goto ERROR;
344
345 // Set the reference
346 *daemon = d;
347
348 return 0;
349
350 ERROR:
351 nw_daemon_unref(d);
352
353 return r;
354 }
355
356 static void nw_daemon_cleanup(nw_daemon* daemon) {
357 if (daemon->ports)
358 nw_ports_unref(daemon->ports);
359 if (daemon->zones)
360 nw_zones_unref(daemon->zones);
361 if (daemon->links)
362 nw_links_unref(daemon->links);
363 if (daemon->config)
364 nw_config_unref(daemon->config);
365 }
366
367 static void nw_daemon_free(nw_daemon* daemon) {
368 // Cleanup common objects
369 nw_daemon_cleanup(daemon);
370
371 if (daemon->bus)
372 sd_bus_unref(daemon->bus);
373 if (daemon->loop)
374 sd_event_unref(daemon->loop);
375
376 free(daemon);
377 }
378
379 nw_daemon* nw_daemon_ref(nw_daemon* daemon) {
380 daemon->nrefs++;
381
382 return daemon;
383 }
384
385 nw_daemon* nw_daemon_unref(nw_daemon* daemon) {
386 if (--daemon->nrefs > 0)
387 return daemon;
388
389 nw_daemon_free(daemon);
390 return NULL;
391 }
392
393 /*
394 This function contains the main loop of the daemon...
395 */
396 int nw_daemon_run(nw_daemon* daemon) {
397 int r;
398
399 // We are now ready to process any requests
400 sd_notify(0, "READY=1\n" "STATUS=Processing requests...");
401
402 // Launch the event loop
403 r = sd_event_loop(daemon->loop);
404 if (r < 0) {
405 ERROR("Could not run the event loop: %s\n", strerror(-r));
406 goto ERROR;
407 }
408
409 // Let systemd know that we are shutting down
410 sd_notify(0, "STOPPING=1\n" "STATUS=Shutting down...");
411
412 // Save the configuration
413 r = nw_daemon_save(daemon);
414 if (r)
415 goto ERROR;
416
417 // Cleanup everything
418 nw_daemon_cleanup(daemon);
419
420 return 0;
421
422 ERROR:
423 sd_notifyf(0, "ERRNO=%i", -r);
424
425 // Cleanup everything
426 nw_daemon_cleanup(daemon);
427
428 return 1;
429 }
430
431 int nw_daemon_reload(nw_daemon* daemon) {
432 DEBUG("Reloading daemon...\n");
433
434 // XXX TODO
435
436 return 0;
437 }
438
439 /*
440 Saves the configuration to disk
441 */
442 int nw_daemon_save(nw_daemon* daemon) {
443 int r;
444
445 DEBUG("Saving configuration...\n");
446
447 // Save settings
448 r = nw_config_write(daemon->config);
449 if (r)
450 return r;
451
452 // Save ports
453 r = nw_ports_save(daemon->ports);
454 if (r)
455 return r;
456
457 // Save zones
458 r = nw_zones_save(daemon->zones);
459 if (r)
460 return r;
461
462 return 0;
463 }
464
465 /*
466 Netlink
467 */
468 sd_netlink* nw_daemon_get_rtnl(nw_daemon* daemon) {
469 return daemon->rtnl;
470 }
471
472 /*
473 Links
474 */
475 nw_links* nw_daemon_links(nw_daemon* daemon) {
476 return nw_links_ref(daemon->links);
477 }
478
479 void nw_daemon_drop_link(nw_daemon* daemon, nw_link* link) {
480 if (!daemon->links)
481 return;
482
483 nw_links_drop_link(daemon->links, link);
484 }
485
486 nw_link* nw_daemon_get_link_by_ifindex(nw_daemon* daemon, int ifindex) {
487 if (!daemon->links)
488 return NULL;
489
490 return nw_links_get_by_ifindex(daemon->links, ifindex);
491 }
492
493 nw_link* nw_daemon_get_link_by_name(nw_daemon* daemon, const char* name) {
494 if (!daemon->links)
495 return NULL;
496
497 return nw_links_get_by_name(daemon->links, name);
498 }
499
500 /*
501 Ports
502 */
503 nw_ports* nw_daemon_ports(nw_daemon* daemon) {
504 return nw_ports_ref(daemon->ports);
505 }
506
507 nw_port* nw_daemon_get_port_by_name(nw_daemon* daemon, const char* name) {
508 if (!daemon->ports)
509 return NULL;
510
511 return nw_ports_get_by_name(daemon->ports, name);
512 }
513
514 /*
515 Zones
516 */
517
518 nw_zones* nw_daemon_zones(nw_daemon* daemon) {
519 return nw_zones_ref(daemon->zones);
520 }
521
522 nw_zone* nw_daemon_get_zone_by_name(nw_daemon* daemon, const char* name) {
523 if (!daemon->zones)
524 return NULL;
525
526 return nw_zones_get_by_name(daemon->zones, name);
527 }