Coverage Report

Created: 2026-08-08 06:57

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/systemd/src/network/networkd-manager-bus.c
Line
Count
Source
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3
#include <sys/stat.h>
4
5
#include "sd-bus.h"
6
7
#include "alloc-util.h"
8
#include "bus-common-errors.h"
9
#include "bus-message-util.h"
10
#include "bus-object.h"
11
#include "bus-polkit.h"
12
#include "hashmap.h"
13
#include "networkd-dhcp-server-bus.h"
14
#include "networkd-dhcp4-bus.h"
15
#include "networkd-dhcp6-bus.h"
16
#include "networkd-json.h"
17
#include "networkd-link.h"
18
#include "networkd-link-bus.h"
19
#include "networkd-manager.h"
20
#include "networkd-manager-bus.h"
21
#include "networkd-network-bus.h"
22
#include "path-util.h"
23
24
0
static int method_list_links(sd_bus_message *message, void *userdata, sd_bus_error *error) {
25
0
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
26
0
        Manager *manager = userdata;
27
0
        Link *link;
28
0
        int r;
29
30
0
        r = sd_bus_message_new_method_return(message, &reply);
31
0
        if (r < 0)
32
0
                return r;
33
34
0
        r = sd_bus_message_open_container(reply, 'a', "(iso)");
35
0
        if (r < 0)
36
0
                return r;
37
38
0
        HASHMAP_FOREACH(link, manager->links_by_index) {
39
0
                _cleanup_free_ char *path = NULL;
40
41
0
                path = link_bus_path(link);
42
0
                if (!path)
43
0
                        return -ENOMEM;
44
45
0
                r = sd_bus_message_append(
46
0
                        reply, "(iso)",
47
0
                        link->ifindex,
48
0
                        link->ifname,
49
0
                        empty_to_root(path));
50
0
                if (r < 0)
51
0
                        return r;
52
0
        }
53
54
0
        r = sd_bus_message_close_container(reply);
55
0
        if (r < 0)
56
0
                return r;
57
58
0
        return sd_bus_message_send(reply);
59
0
}
60
61
0
static int method_get_link_by_name(sd_bus_message *message, void *userdata, sd_bus_error *error) {
62
0
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
63
0
        _cleanup_free_ char *path = NULL;
64
0
        Manager *manager = userdata;
65
0
        const char *name;
66
0
        Link *link;
67
0
        int r;
68
69
0
        r = sd_bus_message_read(message, "s", &name);
70
0
        if (r < 0)
71
0
                return r;
72
73
0
        if (link_get_by_name(manager, name, &link) < 0)
74
0
                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %s not known", name);
75
76
0
        r = sd_bus_message_new_method_return(message, &reply);
77
0
        if (r < 0)
78
0
                return r;
79
80
0
        path = link_bus_path(link);
81
0
        if (!path)
82
0
                return -ENOMEM;
83
84
0
        r = sd_bus_message_append(reply, "io", link->ifindex, empty_to_root(path));
85
0
        if (r < 0)
86
0
                return r;
87
88
0
        return sd_bus_message_send(reply);
89
0
}
90
91
0
static int method_get_link_by_index(sd_bus_message *message, void *userdata, sd_bus_error *error) {
92
0
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
93
0
        _cleanup_free_ char *path = NULL;
94
0
        Manager *manager = userdata;
95
0
        int ifindex, r;
96
0
        Link *link;
97
98
0
        r = bus_message_read_ifindex(message, error, &ifindex);
99
0
        if (r < 0)
100
0
                return r;
101
102
0
        r = link_get_by_index(manager, ifindex, &link);
103
0
        if (r < 0)
104
0
                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
105
106
0
        r = sd_bus_message_new_method_return(message, &reply);
107
0
        if (r < 0)
108
0
                return r;
109
110
0
        path = link_bus_path(link);
111
0
        if (!path)
112
0
                return -ENOMEM;
113
114
0
        r = sd_bus_message_append(reply, "so", link->ifname, empty_to_root(path));
115
0
        if (r < 0)
116
0
                return r;
117
118
0
        return sd_bus_message_send(reply);
119
0
}
120
121
0
static int call_link_method(Manager *m, sd_bus_message *message, sd_bus_message_handler_t handler, sd_bus_error *error) {
122
0
        int ifindex, r;
123
0
        Link *l;
124
125
0
        assert(m);
126
0
        assert(message);
127
0
        assert(handler);
128
129
0
        r = bus_message_read_ifindex(message, error, &ifindex);
130
0
        if (r < 0)
131
0
                return r;
132
133
0
        r = link_get_by_index(m, ifindex, &l);
134
0
        if (r < 0)
135
0
                return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_LINK, "Link %i not known", ifindex);
136
137
0
        return handler(message, l, error);
138
0
}
139
140
0
static int bus_method_set_link_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
141
0
        return call_link_method(userdata, message, bus_link_method_set_ntp_servers, error);
142
0
}
143
144
0
static int bus_method_set_link_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
145
0
        return call_link_method(userdata, message, bus_link_method_set_dns_servers, error);
146
0
}
147
148
0
static int bus_method_set_link_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
149
0
        return call_link_method(userdata, message, bus_link_method_set_dns_servers_ex, error);
150
0
}
151
152
0
static int bus_method_set_link_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
153
0
        return call_link_method(userdata, message, bus_link_method_set_domains, error);
154
0
}
155
156
0
static int bus_method_set_link_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
157
0
        return call_link_method(userdata, message, bus_link_method_set_default_route, error);
158
0
}
159
160
0
static int bus_method_set_link_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
161
0
        return call_link_method(userdata, message, bus_link_method_set_llmnr, error);
162
0
}
163
164
0
static int bus_method_set_link_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
165
0
        return call_link_method(userdata, message, bus_link_method_set_mdns, error);
166
0
}
167
168
0
static int bus_method_set_link_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
169
0
        return call_link_method(userdata, message, bus_link_method_set_dns_over_tls, error);
170
0
}
171
172
0
static int bus_method_set_link_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
173
0
        return call_link_method(userdata, message, bus_link_method_set_dnssec, error);
174
0
}
175
176
0
static int bus_method_set_link_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
177
0
        return call_link_method(userdata, message, bus_link_method_set_dnssec_negative_trust_anchors, error);
178
0
}
179
180
0
static int bus_method_revert_link_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
181
0
        return call_link_method(userdata, message, bus_link_method_revert_ntp, error);
182
0
}
183
184
0
static int bus_method_revert_link_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
185
0
        return call_link_method(userdata, message, bus_link_method_revert_dns, error);
186
0
}
187
188
0
static int bus_method_renew_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
189
0
        return call_link_method(userdata, message, bus_link_method_renew, error);
190
0
}
191
192
0
static int bus_method_force_renew_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
193
0
        return call_link_method(userdata, message, bus_link_method_force_renew, error);
194
0
}
195
196
0
static int bus_method_reconfigure_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
197
0
        return call_link_method(userdata, message, bus_link_method_reconfigure, error);
198
0
}
199
200
0
static int bus_method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) {
201
0
        Manager *manager = ASSERT_PTR(userdata);
202
0
        int r;
203
204
0
        if (manager->reloading > 0)
205
0
                return sd_bus_error_set(error, BUS_ERROR_NETWORK_ALREADY_RELOADING, "Already reloading.");
206
207
0
        r = bus_verify_polkit_async(
208
0
                        message,
209
0
                        "org.freedesktop.network1.reload",
210
0
                        /* details= */ NULL,
211
0
                        &manager->polkit_registry,
212
0
                        error);
213
0
        if (r < 0)
214
0
                return r;
215
0
        if (r == 0)
216
0
                return 1; /* Polkit will call us back */
217
218
0
        r = manager_reload(manager, message, /* varlink= */ NULL, /* reconfigure_links= */ true);
219
0
        if (r < 0)
220
0
                return r;
221
222
0
        if (manager->reloading > 0)
223
0
                return 1; /* Will reply later. */
224
225
0
        return sd_bus_reply_method_return(message, NULL);
226
0
}
227
228
0
static int bus_method_describe_link(sd_bus_message *message, void *userdata, sd_bus_error *error) {
229
0
        return call_link_method(userdata, message, bus_link_method_describe, error);
230
0
}
231
232
0
static int bus_method_describe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
233
0
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
234
0
        _cleanup_(sd_json_variant_unrefp) sd_json_variant *v = NULL;
235
0
        _cleanup_free_ char *text = NULL;
236
0
        Manager *manager = ASSERT_PTR(userdata);
237
0
        int r;
238
239
0
        assert(message);
240
241
0
        r = manager_build_json(manager, &v);
242
0
        if (r < 0)
243
0
                return log_error_errno(r, "Failed to build JSON data: %m");
244
245
0
        r = sd_json_variant_format(v, 0, &text);
246
0
        if (r < 0)
247
0
                return log_error_errno(r, "Failed to format JSON data: %m");
248
249
0
        r = sd_bus_message_new_method_return(message, &reply);
250
0
        if (r < 0)
251
0
                return r;
252
253
0
        r = sd_bus_message_append(reply, "s", text);
254
0
        if (r < 0)
255
0
                return r;
256
257
0
        return sd_bus_message_send(reply);
258
0
}
259
260
static int property_get_namespace_id(
261
                sd_bus *bus,
262
                const char *path,
263
                const char *interface,
264
                const char *property,
265
                sd_bus_message *reply,
266
                void *userdata,
267
0
                sd_bus_error *error) {
268
269
0
        uint64_t id = 0;
270
0
        struct stat st;
271
272
0
        assert(bus);
273
0
        assert(reply);
274
275
        /* Returns our own network namespace ID, i.e. the inode number of /proc/self/ns/net. This allows
276
         * unprivileged clients to determine whether they are in the same network namespace as us (note that
277
         * access to that path is restricted, thus they can't check directly unless privileged). */
278
279
0
        if (stat("/proc/self/ns/net", &st) < 0) {
280
0
                log_warning_errno(errno, "Failed to stat network namespace, ignoring: %m");
281
0
                id = 0;
282
0
        } else
283
0
                id = st.st_ino;
284
285
0
        return sd_bus_message_append(reply, "t", id);
286
0
}
287
288
static int property_get_namespace_nsid(
289
                sd_bus *bus,
290
                const char *path,
291
                const char *interface,
292
                const char *property,
293
                sd_bus_message *reply,
294
                void *userdata,
295
0
                sd_bus_error *error) {
296
297
0
        uint32_t nsid = UINT32_MAX;
298
0
        int r;
299
300
0
        assert(bus);
301
0
        assert(reply);
302
303
        /* Returns our own "nsid", which is another ID for the network namespace, different from the inode
304
         * number. */
305
306
0
        r = netns_get_nsid(/* netnsfd= */ -EBADF, &nsid);
307
0
        if (r < 0 && r != -ENODATA)
308
0
                log_warning_errno(r, "Failed to query network nsid, ignoring: %m");
309
310
0
        return sd_bus_message_append(reply, "u", nsid);
311
0
}
312
313
static const sd_bus_vtable manager_vtable[] = {
314
        SD_BUS_VTABLE_START(0),
315
316
        SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Manager, operational_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
317
        SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Manager, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
318
        SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Manager, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
319
        SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Manager, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
320
        SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Manager, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
321
        SD_BUS_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Manager, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
322
        SD_BUS_PROPERTY("NamespaceId", "t", property_get_namespace_id, 0, SD_BUS_VTABLE_PROPERTY_CONST),
323
        SD_BUS_PROPERTY("NamespaceNSID", "u", property_get_namespace_nsid, 0, 0),
324
325
        SD_BUS_METHOD_WITH_ARGS("ListLinks",
326
                                SD_BUS_NO_ARGS,
327
                                SD_BUS_RESULT("a(iso)", links),
328
                                method_list_links,
329
                                SD_BUS_VTABLE_UNPRIVILEGED),
330
        SD_BUS_METHOD_WITH_ARGS("GetLinkByName",
331
                                SD_BUS_ARGS("s", name),
332
                                SD_BUS_RESULT("i", ifindex, "o", path),
333
                                method_get_link_by_name,
334
                                SD_BUS_VTABLE_UNPRIVILEGED),
335
        SD_BUS_METHOD_WITH_ARGS("GetLinkByIndex",
336
                                SD_BUS_ARGS("i", ifindex),
337
                                SD_BUS_RESULT("s", name, "o", path),
338
                                method_get_link_by_index,
339
                                SD_BUS_VTABLE_UNPRIVILEGED),
340
        SD_BUS_METHOD_WITH_ARGS("SetLinkNTP",
341
                                SD_BUS_ARGS("i", ifindex, "as", servers),
342
                                SD_BUS_NO_RESULT,
343
                                bus_method_set_link_ntp_servers,
344
                                SD_BUS_VTABLE_UNPRIVILEGED),
345
        SD_BUS_METHOD_WITH_ARGS("SetLinkDNS",
346
                                SD_BUS_ARGS("i", ifindex, "a(iay)", addresses),
347
                                SD_BUS_NO_RESULT,
348
                                bus_method_set_link_dns_servers,
349
                                SD_BUS_VTABLE_UNPRIVILEGED),
350
        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSEx",
351
                                SD_BUS_ARGS("i", ifindex, "a(iayqs)", addresses),
352
                                SD_BUS_NO_RESULT,
353
                                bus_method_set_link_dns_servers_ex,
354
                                SD_BUS_VTABLE_UNPRIVILEGED),
355
        SD_BUS_METHOD_WITH_ARGS("SetLinkDomains",
356
                                SD_BUS_ARGS("i", ifindex, "a(sb)", domains),
357
                                SD_BUS_NO_RESULT,
358
                                bus_method_set_link_domains,
359
                                SD_BUS_VTABLE_UNPRIVILEGED),
360
        SD_BUS_METHOD_WITH_ARGS("SetLinkDefaultRoute",
361
                                SD_BUS_ARGS("i", ifindex, "b", enable),
362
                                SD_BUS_NO_RESULT,
363
                                bus_method_set_link_default_route,
364
                                SD_BUS_VTABLE_UNPRIVILEGED),
365
        SD_BUS_METHOD_WITH_ARGS("SetLinkLLMNR",
366
                                SD_BUS_ARGS("i", ifindex, "s", mode),
367
                                SD_BUS_NO_RESULT,
368
                                bus_method_set_link_llmnr,
369
                                SD_BUS_VTABLE_UNPRIVILEGED),
370
        SD_BUS_METHOD_WITH_ARGS("SetLinkMulticastDNS",
371
                                SD_BUS_ARGS("i", ifindex, "s", mode),
372
                                SD_BUS_NO_RESULT,
373
                                bus_method_set_link_mdns,
374
                                SD_BUS_VTABLE_UNPRIVILEGED),
375
        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSOverTLS",
376
                                SD_BUS_ARGS("i", ifindex, "s", mode),
377
                                SD_BUS_NO_RESULT,
378
                                bus_method_set_link_dns_over_tls,
379
                                SD_BUS_VTABLE_UNPRIVILEGED),
380
        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSEC",
381
                                SD_BUS_ARGS("i", ifindex, "s", mode),
382
                                SD_BUS_NO_RESULT,
383
                                bus_method_set_link_dnssec,
384
                                SD_BUS_VTABLE_UNPRIVILEGED),
385
        SD_BUS_METHOD_WITH_ARGS("SetLinkDNSSECNegativeTrustAnchors",
386
                                SD_BUS_ARGS("i", ifindex, "as", names),
387
                                SD_BUS_NO_RESULT,
388
                                bus_method_set_link_dnssec_negative_trust_anchors,
389
                                SD_BUS_VTABLE_UNPRIVILEGED),
390
        SD_BUS_METHOD_WITH_ARGS("RevertLinkNTP",
391
                                SD_BUS_ARGS("i", ifindex),
392
                                SD_BUS_NO_RESULT,
393
                                bus_method_revert_link_ntp,
394
                                SD_BUS_VTABLE_UNPRIVILEGED),
395
        SD_BUS_METHOD_WITH_ARGS("RevertLinkDNS",
396
                                SD_BUS_ARGS("i", ifindex),
397
                                SD_BUS_NO_RESULT,
398
                                bus_method_revert_link_dns,
399
                                SD_BUS_VTABLE_UNPRIVILEGED),
400
        SD_BUS_METHOD_WITH_ARGS("RenewLink",
401
                                SD_BUS_ARGS("i", ifindex),
402
                                SD_BUS_NO_RESULT,
403
                                bus_method_renew_link,
404
                                SD_BUS_VTABLE_UNPRIVILEGED),
405
        SD_BUS_METHOD_WITH_ARGS("ForceRenewLink",
406
                                SD_BUS_ARGS("i", ifindex),
407
                                SD_BUS_NO_RESULT,
408
                                bus_method_force_renew_link,
409
                                SD_BUS_VTABLE_UNPRIVILEGED),
410
        SD_BUS_METHOD_WITH_ARGS("ReconfigureLink",
411
                                SD_BUS_ARGS("i", ifindex),
412
                                SD_BUS_NO_RESULT,
413
                                bus_method_reconfigure_link,
414
                                SD_BUS_VTABLE_UNPRIVILEGED),
415
        SD_BUS_METHOD_WITH_ARGS("Reload",
416
                                SD_BUS_NO_ARGS,
417
                                SD_BUS_NO_RESULT,
418
                                bus_method_reload,
419
                                SD_BUS_VTABLE_UNPRIVILEGED),
420
        SD_BUS_METHOD_WITH_ARGS("DescribeLink",
421
                                SD_BUS_ARGS("i", ifindex),
422
                                SD_BUS_RESULT("s", json),
423
                                bus_method_describe_link,
424
                                SD_BUS_VTABLE_UNPRIVILEGED),
425
        SD_BUS_METHOD_WITH_ARGS("Describe",
426
                                SD_BUS_NO_ARGS,
427
                                SD_BUS_RESULT("s", json),
428
                                bus_method_describe,
429
                                SD_BUS_VTABLE_UNPRIVILEGED),
430
431
        SD_BUS_VTABLE_END
432
};
433
434
0
int manager_send_changed_strv(Manager *manager, char **properties) {
435
0
        assert(manager);
436
0
        assert(properties);
437
438
0
        if (sd_bus_is_ready(manager->bus) <= 0)
439
0
                return 0;
440
441
0
        return sd_bus_emit_properties_changed_strv(
442
0
                        manager->bus,
443
0
                        "/org/freedesktop/network1",
444
0
                        "org.freedesktop.network1.Manager",
445
0
                        properties);
446
0
}
447
448
const BusObjectImplementation manager_object = {
449
        "/org/freedesktop/network1",
450
        "org.freedesktop.network1.Manager",
451
        .vtables = BUS_VTABLES(manager_vtable),
452
        .children = BUS_IMPLEMENTATIONS(
453
                        &link_object, /* This is the main implementation for /org/freedesktop/network1/link,
454
                                       * and must be earlier than the dhcp objects below. */
455
                        &dhcp_server_object,
456
                        &dhcp_client_object,
457
                        &dhcp6_client_object,
458
                        &network_object),
459
};