1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2
3 #include <net/if.h>
4 #include <netinet/in.h>
5 #include <sys/capability.h>
6
7 #include "alloc-util.h"
8 #include "bus-common-errors.h"
9 #include "bus-get-properties.h"
10 #include "bus-message-util.h"
11 #include "bus-polkit.h"
12 #include "dns-domain.h"
13 #include "networkd-json.h"
14 #include "networkd-link-bus.h"
15 #include "networkd-link.h"
16 #include "networkd-manager.h"
17 #include "networkd-state-file.h"
18 #include "parse-util.h"
19 #include "resolve-util.h"
20 #include "socket-netlink.h"
21 #include "strv.h"
22 #include "user-util.h"
23
24 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_operational_state, link_operstate, LinkOperationalState);
25 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_carrier_state, link_carrier_state, LinkCarrierState);
26 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_address_state, link_address_state, LinkAddressState);
27 BUS_DEFINE_PROPERTY_GET_ENUM(property_get_online_state, link_online_state, LinkOnlineState);
28 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_administrative_state, link_state, LinkState);
29
property_get_bit_rates(sd_bus * bus,const char * path,const char * interface,const char * property,sd_bus_message * reply,void * userdata,sd_bus_error * error)30 static int property_get_bit_rates(
31 sd_bus *bus,
32 const char *path,
33 const char *interface,
34 const char *property,
35 sd_bus_message *reply,
36 void *userdata,
37 sd_bus_error *error) {
38
39 Link *link = userdata;
40 Manager *manager;
41 double interval_sec;
42 uint64_t tx, rx;
43
44 assert(bus);
45 assert(reply);
46 assert(userdata);
47
48 manager = link->manager;
49
50 if (!manager->use_speed_meter ||
51 manager->speed_meter_usec_old == 0 ||
52 !link->stats_updated)
53 return sd_bus_message_append(reply, "(tt)", UINT64_MAX, UINT64_MAX);
54
55 assert(manager->speed_meter_usec_new > manager->speed_meter_usec_old);
56 interval_sec = (manager->speed_meter_usec_new - manager->speed_meter_usec_old) / USEC_PER_SEC;
57
58 if (link->stats_new.tx_bytes > link->stats_old.tx_bytes)
59 tx = (uint64_t) ((link->stats_new.tx_bytes - link->stats_old.tx_bytes) / interval_sec);
60 else
61 tx = (uint64_t) ((UINT64_MAX - (link->stats_old.tx_bytes - link->stats_new.tx_bytes)) / interval_sec);
62
63 if (link->stats_new.rx_bytes > link->stats_old.rx_bytes)
64 rx = (uint64_t) ((link->stats_new.rx_bytes - link->stats_old.rx_bytes) / interval_sec);
65 else
66 rx = (uint64_t) ((UINT64_MAX - (link->stats_old.rx_bytes - link->stats_new.rx_bytes)) / interval_sec);
67
68 return sd_bus_message_append(reply, "(tt)", tx, rx);
69 }
70
verify_managed_link(Link * l,sd_bus_error * error)71 static int verify_managed_link(Link *l, sd_bus_error *error) {
72 assert(l);
73
74 if (l->flags & IFF_LOOPBACK)
75 return sd_bus_error_setf(error, BUS_ERROR_LINK_BUSY, "Link %s is loopback device.", l->ifname);
76
77 return 0;
78 }
79
bus_link_method_set_ntp_servers(sd_bus_message * message,void * userdata,sd_bus_error * error)80 int bus_link_method_set_ntp_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
81 _cleanup_strv_free_ char **ntp = NULL;
82 Link *l = userdata;
83 int r;
84
85 assert(message);
86 assert(l);
87
88 r = verify_managed_link(l, error);
89 if (r < 0)
90 return r;
91
92 r = sd_bus_message_read_strv(message, &ntp);
93 if (r < 0)
94 return r;
95
96 STRV_FOREACH(i, ntp) {
97 r = dns_name_is_valid_or_address(*i);
98 if (r < 0)
99 return r;
100 if (r == 0)
101 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid NTP server: %s", *i);
102 }
103
104 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
105 "org.freedesktop.network1.set-ntp-servers",
106 NULL, true, UID_INVALID,
107 &l->manager->polkit_registry, error);
108 if (r < 0)
109 return r;
110 if (r == 0)
111 return 1; /* Polkit will call us back */
112
113 strv_free_and_replace(l->ntp, ntp);
114
115 link_dirty(l);
116 r = link_save_and_clean(l);
117 if (r < 0)
118 return r;
119
120 return sd_bus_reply_method_return(message, NULL);
121 }
122
bus_link_method_set_dns_servers_internal(sd_bus_message * message,void * userdata,sd_bus_error * error,bool extended)123 static int bus_link_method_set_dns_servers_internal(sd_bus_message *message, void *userdata, sd_bus_error *error, bool extended) {
124 struct in_addr_full **dns;
125 Link *l = userdata;
126 size_t n;
127 int r;
128
129 assert(message);
130 assert(l);
131
132 r = verify_managed_link(l, error);
133 if (r < 0)
134 return r;
135
136 r = bus_message_read_dns_servers(message, error, extended, &dns, &n);
137 if (r < 0)
138 return r;
139
140 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
141 "org.freedesktop.network1.set-dns-servers",
142 NULL, true, UID_INVALID,
143 &l->manager->polkit_registry, error);
144 if (r < 0)
145 goto finalize;
146 if (r == 0) {
147 r = 1; /* Polkit will call us back */
148 goto finalize;
149 }
150
151 if (l->n_dns != UINT_MAX)
152 for (unsigned i = 0; i < l->n_dns; i++)
153 in_addr_full_free(l->dns[i]);
154
155 free_and_replace(l->dns, dns);
156 l->n_dns = n;
157
158 link_dirty(l);
159 r = link_save_and_clean(l);
160 if (r < 0)
161 return r;
162
163 return sd_bus_reply_method_return(message, NULL);
164
165 finalize:
166 for (size_t i = 0; i < n; i++)
167 in_addr_full_free(dns[i]);
168 free(dns);
169
170 return r;
171 }
172
bus_link_method_set_dns_servers(sd_bus_message * message,void * userdata,sd_bus_error * error)173 int bus_link_method_set_dns_servers(sd_bus_message *message, void *userdata, sd_bus_error *error) {
174 return bus_link_method_set_dns_servers_internal(message, userdata, error, false);
175 }
176
bus_link_method_set_dns_servers_ex(sd_bus_message * message,void * userdata,sd_bus_error * error)177 int bus_link_method_set_dns_servers_ex(sd_bus_message *message, void *userdata, sd_bus_error *error) {
178 return bus_link_method_set_dns_servers_internal(message, userdata, error, true);
179 }
180
bus_link_method_set_domains(sd_bus_message * message,void * userdata,sd_bus_error * error)181 int bus_link_method_set_domains(sd_bus_message *message, void *userdata, sd_bus_error *error) {
182 _cleanup_ordered_set_free_ OrderedSet *search_domains = NULL, *route_domains = NULL;
183 Link *l = userdata;
184 int r;
185
186 assert(message);
187 assert(l);
188
189 r = verify_managed_link(l, error);
190 if (r < 0)
191 return r;
192
193 r = sd_bus_message_enter_container(message, 'a', "(sb)");
194 if (r < 0)
195 return r;
196
197 search_domains = ordered_set_new(&string_hash_ops_free);
198 if (!search_domains)
199 return -ENOMEM;
200
201 route_domains = ordered_set_new(&string_hash_ops_free);
202 if (!route_domains)
203 return -ENOMEM;
204
205 for (;;) {
206 _cleanup_free_ char *str = NULL;
207 const char *name;
208 int route_only;
209
210 r = sd_bus_message_read(message, "(sb)", &name, &route_only);
211 if (r < 0)
212 return r;
213 if (r == 0)
214 break;
215
216 r = dns_name_is_valid(name);
217 if (r < 0)
218 return r;
219 if (r == 0)
220 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
221 if (!route_only && dns_name_is_root(name))
222 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root domain is not suitable as search domain");
223
224 r = dns_name_normalize(name, 0, &str);
225 if (r < 0)
226 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid search domain %s", name);
227
228 r = ordered_set_consume(route_only ? route_domains : search_domains, TAKE_PTR(str));
229 if (r == -EEXIST)
230 continue;
231 if (r < 0)
232 return r;
233 }
234
235 r = sd_bus_message_exit_container(message);
236 if (r < 0)
237 return r;
238
239 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
240 "org.freedesktop.network1.set-domains",
241 NULL, true, UID_INVALID,
242 &l->manager->polkit_registry, error);
243 if (r < 0)
244 return r;
245 if (r == 0)
246 return 1; /* Polkit will call us back */
247
248 ordered_set_free(l->search_domains);
249 ordered_set_free(l->route_domains);
250 l->search_domains = TAKE_PTR(search_domains);
251 l->route_domains = TAKE_PTR(route_domains);
252
253 link_dirty(l);
254 r = link_save_and_clean(l);
255 if (r < 0)
256 return r;
257
258 return sd_bus_reply_method_return(message, NULL);
259 }
260
bus_link_method_set_default_route(sd_bus_message * message,void * userdata,sd_bus_error * error)261 int bus_link_method_set_default_route(sd_bus_message *message, void *userdata, sd_bus_error *error) {
262 Link *l = userdata;
263 int r, b;
264
265 assert(message);
266 assert(l);
267
268 r = verify_managed_link(l, error);
269 if (r < 0)
270 return r;
271
272 r = sd_bus_message_read(message, "b", &b);
273 if (r < 0)
274 return r;
275
276 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
277 "org.freedesktop.network1.set-default-route",
278 NULL, true, UID_INVALID,
279 &l->manager->polkit_registry, error);
280 if (r < 0)
281 return r;
282 if (r == 0)
283 return 1; /* Polkit will call us back */
284
285 if (l->dns_default_route != b) {
286 l->dns_default_route = b;
287
288 link_dirty(l);
289 r = link_save_and_clean(l);
290 if (r < 0)
291 return r;
292 }
293
294 return sd_bus_reply_method_return(message, NULL);
295 }
296
bus_link_method_set_llmnr(sd_bus_message * message,void * userdata,sd_bus_error * error)297 int bus_link_method_set_llmnr(sd_bus_message *message, void *userdata, sd_bus_error *error) {
298 Link *l = userdata;
299 ResolveSupport mode;
300 const char *llmnr;
301 int r;
302
303 assert(message);
304 assert(l);
305
306 r = verify_managed_link(l, error);
307 if (r < 0)
308 return r;
309
310 r = sd_bus_message_read(message, "s", &llmnr);
311 if (r < 0)
312 return r;
313
314 if (isempty(llmnr))
315 mode = RESOLVE_SUPPORT_YES;
316 else {
317 mode = resolve_support_from_string(llmnr);
318 if (mode < 0)
319 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid LLMNR setting: %s", llmnr);
320 }
321
322 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
323 "org.freedesktop.network1.set-llmnr",
324 NULL, true, UID_INVALID,
325 &l->manager->polkit_registry, error);
326 if (r < 0)
327 return r;
328 if (r == 0)
329 return 1; /* Polkit will call us back */
330
331 if (l->llmnr != mode) {
332 l->llmnr = mode;
333
334 link_dirty(l);
335 r = link_save_and_clean(l);
336 if (r < 0)
337 return r;
338 }
339
340 return sd_bus_reply_method_return(message, NULL);
341 }
342
bus_link_method_set_mdns(sd_bus_message * message,void * userdata,sd_bus_error * error)343 int bus_link_method_set_mdns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
344 Link *l = userdata;
345 ResolveSupport mode;
346 const char *mdns;
347 int r;
348
349 assert(message);
350 assert(l);
351
352 r = verify_managed_link(l, error);
353 if (r < 0)
354 return r;
355
356 r = sd_bus_message_read(message, "s", &mdns);
357 if (r < 0)
358 return r;
359
360 if (isempty(mdns))
361 mode = RESOLVE_SUPPORT_NO;
362 else {
363 mode = resolve_support_from_string(mdns);
364 if (mode < 0)
365 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid MulticastDNS setting: %s", mdns);
366 }
367
368 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
369 "org.freedesktop.network1.set-mdns",
370 NULL, true, UID_INVALID,
371 &l->manager->polkit_registry, error);
372 if (r < 0)
373 return r;
374 if (r == 0)
375 return 1; /* Polkit will call us back */
376
377 if (l->mdns != mode) {
378 l->mdns = mode;
379
380 link_dirty(l);
381 r = link_save_and_clean(l);
382 if (r < 0)
383 return r;
384 }
385
386 return sd_bus_reply_method_return(message, NULL);
387 }
388
bus_link_method_set_dns_over_tls(sd_bus_message * message,void * userdata,sd_bus_error * error)389 int bus_link_method_set_dns_over_tls(sd_bus_message *message, void *userdata, sd_bus_error *error) {
390 Link *l = userdata;
391 const char *dns_over_tls;
392 DnsOverTlsMode mode;
393 int r;
394
395 assert(message);
396 assert(l);
397
398 r = verify_managed_link(l, error);
399 if (r < 0)
400 return r;
401
402 r = sd_bus_message_read(message, "s", &dns_over_tls);
403 if (r < 0)
404 return r;
405
406 if (isempty(dns_over_tls))
407 mode = _DNS_OVER_TLS_MODE_INVALID;
408 else {
409 mode = dns_over_tls_mode_from_string(dns_over_tls);
410 if (mode < 0)
411 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSOverTLS setting: %s", dns_over_tls);
412 }
413
414 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
415 "org.freedesktop.network1.set-dns-over-tls",
416 NULL, true, UID_INVALID,
417 &l->manager->polkit_registry, error);
418 if (r < 0)
419 return r;
420 if (r == 0)
421 return 1; /* Polkit will call us back */
422
423 if (l->dns_over_tls_mode != mode) {
424 l->dns_over_tls_mode = mode;
425
426 link_dirty(l);
427 r = link_save_and_clean(l);
428 if (r < 0)
429 return r;
430 }
431
432 return sd_bus_reply_method_return(message, NULL);
433 }
434
bus_link_method_set_dnssec(sd_bus_message * message,void * userdata,sd_bus_error * error)435 int bus_link_method_set_dnssec(sd_bus_message *message, void *userdata, sd_bus_error *error) {
436 Link *l = userdata;
437 const char *dnssec;
438 DnssecMode mode;
439 int r;
440
441 assert(message);
442 assert(l);
443
444 r = verify_managed_link(l, error);
445 if (r < 0)
446 return r;
447
448 r = sd_bus_message_read(message, "s", &dnssec);
449 if (r < 0)
450 return r;
451
452 if (isempty(dnssec))
453 mode = _DNSSEC_MODE_INVALID;
454 else {
455 mode = dnssec_mode_from_string(dnssec);
456 if (mode < 0)
457 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid DNSSEC setting: %s", dnssec);
458 }
459
460 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
461 "org.freedesktop.network1.set-dnssec",
462 NULL, true, UID_INVALID,
463 &l->manager->polkit_registry, error);
464 if (r < 0)
465 return r;
466 if (r == 0)
467 return 1; /* Polkit will call us back */
468
469 if (l->dnssec_mode != mode) {
470 l->dnssec_mode = mode;
471
472 link_dirty(l);
473 r = link_save_and_clean(l);
474 if (r < 0)
475 return r;
476 }
477
478 return sd_bus_reply_method_return(message, NULL);
479 }
480
bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message * message,void * userdata,sd_bus_error * error)481 int bus_link_method_set_dnssec_negative_trust_anchors(sd_bus_message *message, void *userdata, sd_bus_error *error) {
482 _cleanup_set_free_free_ Set *ns = NULL;
483 _cleanup_strv_free_ char **ntas = NULL;
484 Link *l = userdata;
485 int r;
486
487 assert(message);
488 assert(l);
489
490 r = verify_managed_link(l, error);
491 if (r < 0)
492 return r;
493
494 r = sd_bus_message_read_strv(message, &ntas);
495 if (r < 0)
496 return r;
497
498 STRV_FOREACH(i, ntas) {
499 r = dns_name_is_valid(*i);
500 if (r < 0)
501 return r;
502 if (r == 0)
503 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid negative trust anchor domain: %s", *i);
504 }
505
506 ns = set_new(&dns_name_hash_ops);
507 if (!ns)
508 return -ENOMEM;
509
510 STRV_FOREACH(i, ntas) {
511 r = set_put_strdup(&ns, *i);
512 if (r < 0)
513 return r;
514 }
515
516 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
517 "org.freedesktop.network1.set-dnssec-negative-trust-anchors",
518 NULL, true, UID_INVALID,
519 &l->manager->polkit_registry, error);
520 if (r < 0)
521 return r;
522 if (r == 0)
523 return 1; /* Polkit will call us back */
524
525 set_free_free(l->dnssec_negative_trust_anchors);
526 l->dnssec_negative_trust_anchors = TAKE_PTR(ns);
527
528 link_dirty(l);
529 r = link_save_and_clean(l);
530 if (r < 0)
531 return r;
532
533 return sd_bus_reply_method_return(message, NULL);
534 }
535
bus_link_method_revert_ntp(sd_bus_message * message,void * userdata,sd_bus_error * error)536 int bus_link_method_revert_ntp(sd_bus_message *message, void *userdata, sd_bus_error *error) {
537 Link *l = userdata;
538 int r;
539
540 assert(message);
541 assert(l);
542
543 r = verify_managed_link(l, error);
544 if (r < 0)
545 return r;
546
547 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
548 "org.freedesktop.network1.revert-ntp",
549 NULL, true, UID_INVALID,
550 &l->manager->polkit_registry, error);
551 if (r < 0)
552 return r;
553 if (r == 0)
554 return 1; /* Polkit will call us back */
555
556 link_ntp_settings_clear(l);
557
558 link_dirty(l);
559 r = link_save_and_clean(l);
560 if (r < 0)
561 return r;
562
563 return sd_bus_reply_method_return(message, NULL);
564 }
565
bus_link_method_revert_dns(sd_bus_message * message,void * userdata,sd_bus_error * error)566 int bus_link_method_revert_dns(sd_bus_message *message, void *userdata, sd_bus_error *error) {
567 Link *l = userdata;
568 int r;
569
570 assert(message);
571 assert(l);
572
573 r = verify_managed_link(l, error);
574 if (r < 0)
575 return r;
576
577 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
578 "org.freedesktop.network1.revert-dns",
579 NULL, true, UID_INVALID,
580 &l->manager->polkit_registry, error);
581 if (r < 0)
582 return r;
583 if (r == 0)
584 return 1; /* Polkit will call us back */
585
586 link_dns_settings_clear(l);
587
588 link_dirty(l);
589 r = link_save_and_clean(l);
590 if (r < 0)
591 return r;
592
593 return sd_bus_reply_method_return(message, NULL);
594 }
595
bus_link_method_force_renew(sd_bus_message * message,void * userdata,sd_bus_error * error)596 int bus_link_method_force_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
597 Link *l = userdata;
598 int r;
599
600 assert(l);
601
602 if (!l->network)
603 return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
604 "Interface %s is not managed by systemd-networkd",
605 l->ifname);
606
607 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
608 "org.freedesktop.network1.forcerenew",
609 NULL, true, UID_INVALID,
610 &l->manager->polkit_registry, error);
611 if (r < 0)
612 return r;
613 if (r == 0)
614 return 1; /* Polkit will call us back */
615
616 if (l->dhcp_server) {
617 r = sd_dhcp_server_forcerenew(l->dhcp_server);
618 if (r < 0)
619 return r;
620 }
621
622 return sd_bus_reply_method_return(message, NULL);
623 }
624
bus_link_method_renew(sd_bus_message * message,void * userdata,sd_bus_error * error)625 int bus_link_method_renew(sd_bus_message *message, void *userdata, sd_bus_error *error) {
626 Link *l = userdata;
627 int r;
628
629 assert(l);
630
631 if (!l->network)
632 return sd_bus_error_setf(error, BUS_ERROR_UNMANAGED_INTERFACE,
633 "Interface %s is not managed by systemd-networkd",
634 l->ifname);
635
636 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
637 "org.freedesktop.network1.renew",
638 NULL, true, UID_INVALID,
639 &l->manager->polkit_registry, error);
640 if (r < 0)
641 return r;
642 if (r == 0)
643 return 1; /* Polkit will call us back */
644
645 if (l->dhcp_client) {
646 r = sd_dhcp_client_send_renew(l->dhcp_client);
647 if (r < 0)
648 return r;
649 }
650
651 return sd_bus_reply_method_return(message, NULL);
652 }
653
bus_link_method_reconfigure(sd_bus_message * message,void * userdata,sd_bus_error * error)654 int bus_link_method_reconfigure(sd_bus_message *message, void *userdata, sd_bus_error *error) {
655 Link *l = userdata;
656 int r;
657
658 assert(message);
659 assert(l);
660
661 r = bus_verify_polkit_async(message, CAP_NET_ADMIN,
662 "org.freedesktop.network1.reconfigure",
663 NULL, true, UID_INVALID,
664 &l->manager->polkit_registry, error);
665 if (r < 0)
666 return r;
667 if (r == 0)
668 return 1; /* Polkit will call us back */
669
670 r = link_reconfigure(l, /* force = */ true);
671 if (r < 0)
672 return r;
673 if (r > 0) {
674 link_set_state(l, LINK_STATE_INITIALIZED);
675 r = link_save_and_clean(l);
676 if (r < 0)
677 return r;
678 }
679
680 return sd_bus_reply_method_return(message, NULL);
681 }
682
bus_link_method_describe(sd_bus_message * message,void * userdata,sd_bus_error * error)683 int bus_link_method_describe(sd_bus_message *message, void *userdata, sd_bus_error *error) {
684 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
685 _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
686 _cleanup_free_ char *text = NULL;
687 Link *link = userdata;
688 int r;
689
690 assert(message);
691 assert(link);
692
693 r = link_build_json(link, &v);
694 if (r < 0)
695 return log_link_error_errno(link, r, "Failed to build JSON data: %m");
696
697 r = json_variant_format(v, 0, &text);
698 if (r < 0)
699 return log_link_error_errno(link, r, "Failed to format JSON data: %m");
700
701 r = sd_bus_message_new_method_return(message, &reply);
702 if (r < 0)
703 return r;
704
705 r = sd_bus_message_append(reply, "s", text);
706 if (r < 0)
707 return r;
708
709 return sd_bus_send(NULL, reply, NULL);
710 }
711
712 static const sd_bus_vtable link_vtable[] = {
713 SD_BUS_VTABLE_START(0),
714
715 SD_BUS_PROPERTY("OperationalState", "s", property_get_operational_state, offsetof(Link, operstate), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
716 SD_BUS_PROPERTY("CarrierState", "s", property_get_carrier_state, offsetof(Link, carrier_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
717 SD_BUS_PROPERTY("AddressState", "s", property_get_address_state, offsetof(Link, address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
718 SD_BUS_PROPERTY("IPv4AddressState", "s", property_get_address_state, offsetof(Link, ipv4_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
719 SD_BUS_PROPERTY("IPv6AddressState", "s", property_get_address_state, offsetof(Link, ipv6_address_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
720 SD_BUS_PROPERTY("OnlineState", "s", property_get_online_state, offsetof(Link, online_state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
721 SD_BUS_PROPERTY("AdministrativeState", "s", property_get_administrative_state, offsetof(Link, state), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE),
722 SD_BUS_PROPERTY("BitRates", "(tt)", property_get_bit_rates, 0, 0),
723
724 SD_BUS_METHOD_WITH_ARGS("SetNTP",
725 SD_BUS_ARGS("as", servers),
726 SD_BUS_NO_RESULT,
727 bus_link_method_set_ntp_servers,
728 SD_BUS_VTABLE_UNPRIVILEGED),
729 SD_BUS_METHOD_WITH_ARGS("SetDNS",
730 SD_BUS_ARGS("a(iay)", addresses),
731 SD_BUS_NO_RESULT,
732 bus_link_method_set_dns_servers,
733 SD_BUS_VTABLE_UNPRIVILEGED),
734 SD_BUS_METHOD_WITH_ARGS("SetDNSEx",
735 SD_BUS_ARGS("a(iayqs)", addresses),
736 SD_BUS_NO_RESULT,
737 bus_link_method_set_dns_servers_ex,
738 SD_BUS_VTABLE_UNPRIVILEGED),
739 SD_BUS_METHOD_WITH_ARGS("SetDomains",
740 SD_BUS_ARGS("a(sb)", domains),
741 SD_BUS_NO_RESULT,
742 bus_link_method_set_domains,
743 SD_BUS_VTABLE_UNPRIVILEGED),
744 SD_BUS_METHOD_WITH_ARGS("SetDefaultRoute",
745 SD_BUS_ARGS("b", enable),
746 SD_BUS_NO_RESULT,
747 bus_link_method_set_default_route,
748 SD_BUS_VTABLE_UNPRIVILEGED),
749 SD_BUS_METHOD_WITH_ARGS("SetLLMNR",
750 SD_BUS_ARGS("s", mode),
751 SD_BUS_NO_RESULT,
752 bus_link_method_set_llmnr,
753 SD_BUS_VTABLE_UNPRIVILEGED),
754 SD_BUS_METHOD_WITH_ARGS("SetMulticastDNS",
755 SD_BUS_ARGS("s", mode),
756 SD_BUS_NO_RESULT,
757 bus_link_method_set_mdns,
758 SD_BUS_VTABLE_UNPRIVILEGED),
759 SD_BUS_METHOD_WITH_ARGS("SetDNSOverTLS",
760 SD_BUS_ARGS("s", mode),
761 SD_BUS_NO_RESULT,
762 bus_link_method_set_dns_over_tls,
763 SD_BUS_VTABLE_UNPRIVILEGED),
764 SD_BUS_METHOD_WITH_ARGS("SetDNSSEC",
765 SD_BUS_ARGS("s", mode),
766 SD_BUS_NO_RESULT,
767 bus_link_method_set_dnssec,
768 SD_BUS_VTABLE_UNPRIVILEGED),
769 SD_BUS_METHOD_WITH_ARGS("SetDNSSECNegativeTrustAnchors",
770 SD_BUS_ARGS("as", names),
771 SD_BUS_NO_RESULT,
772 bus_link_method_set_dnssec_negative_trust_anchors,
773 SD_BUS_VTABLE_UNPRIVILEGED),
774 SD_BUS_METHOD_WITH_ARGS("RevertNTP",
775 SD_BUS_NO_ARGS,
776 SD_BUS_NO_RESULT,
777 bus_link_method_revert_ntp,
778 SD_BUS_VTABLE_UNPRIVILEGED),
779 SD_BUS_METHOD_WITH_ARGS("RevertDNS",
780 SD_BUS_NO_ARGS,
781 SD_BUS_NO_RESULT,
782 bus_link_method_revert_dns,
783 SD_BUS_VTABLE_UNPRIVILEGED),
784 SD_BUS_METHOD_WITH_ARGS("Renew",
785 SD_BUS_NO_ARGS,
786 SD_BUS_NO_RESULT,
787 bus_link_method_renew,
788 SD_BUS_VTABLE_UNPRIVILEGED),
789 SD_BUS_METHOD_WITH_ARGS("ForceRenew",
790 SD_BUS_NO_ARGS,
791 SD_BUS_NO_RESULT,
792 bus_link_method_force_renew,
793 SD_BUS_VTABLE_UNPRIVILEGED),
794 SD_BUS_METHOD_WITH_ARGS("Reconfigure",
795 SD_BUS_NO_ARGS,
796 SD_BUS_NO_RESULT,
797 bus_link_method_reconfigure,
798 SD_BUS_VTABLE_UNPRIVILEGED),
799 SD_BUS_METHOD_WITH_ARGS("Describe",
800 SD_BUS_NO_ARGS,
801 SD_BUS_RESULT("s", json),
802 bus_link_method_describe,
803 SD_BUS_VTABLE_UNPRIVILEGED),
804
805 SD_BUS_VTABLE_END
806 };
807
link_bus_path(Link * link)808 char *link_bus_path(Link *link) {
809 _cleanup_free_ char *ifindex = NULL;
810 char *p;
811 int r;
812
813 assert(link);
814 assert(link->ifindex > 0);
815
816 if (asprintf(&ifindex, "%d", link->ifindex) < 0)
817 return NULL;
818
819 r = sd_bus_path_encode("/org/freedesktop/network1/link", ifindex, &p);
820 if (r < 0)
821 return NULL;
822
823 return p;
824 }
825
link_node_enumerator(sd_bus * bus,const char * path,void * userdata,char *** nodes,sd_bus_error * error)826 int link_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
827 _cleanup_strv_free_ char **l = NULL;
828 Manager *m = userdata;
829 unsigned c = 0;
830 Link *link;
831
832 assert(bus);
833 assert(path);
834 assert(m);
835 assert(nodes);
836
837 l = new0(char*, hashmap_size(m->links_by_index) + 1);
838 if (!l)
839 return -ENOMEM;
840
841 HASHMAP_FOREACH(link, m->links_by_index) {
842 char *p;
843
844 p = link_bus_path(link);
845 if (!p)
846 return -ENOMEM;
847
848 l[c++] = p;
849 }
850
851 l[c] = NULL;
852 *nodes = TAKE_PTR(l);
853
854 return 1;
855 }
856
link_object_find(sd_bus * bus,const char * path,const char * interface,void * userdata,void ** found,sd_bus_error * error)857 int link_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
858 _cleanup_free_ char *identifier = NULL;
859 Manager *m = userdata;
860 Link *link;
861 int ifindex, r;
862
863 assert(bus);
864 assert(path);
865 assert(interface);
866 assert(m);
867 assert(found);
868
869 r = sd_bus_path_decode(path, "/org/freedesktop/network1/link", &identifier);
870 if (r <= 0)
871 return 0;
872
873 ifindex = parse_ifindex(identifier);
874 if (ifindex < 0)
875 return 0;
876
877 r = link_get_by_index(m, ifindex, &link);
878 if (r < 0)
879 return 0;
880
881 if (streq(interface, "org.freedesktop.network1.DHCPServer") && !link->dhcp_server)
882 return 0;
883
884 *found = link;
885
886 return 1;
887 }
888
link_send_changed_strv(Link * link,char ** properties)889 int link_send_changed_strv(Link *link, char **properties) {
890 _cleanup_free_ char *p = NULL;
891
892 assert(link);
893 assert(link->manager);
894 assert(properties);
895
896 if (sd_bus_is_ready(link->manager->bus) <= 0)
897 return 0;
898
899 p = link_bus_path(link);
900 if (!p)
901 return -ENOMEM;
902
903 return sd_bus_emit_properties_changed_strv(
904 link->manager->bus,
905 p,
906 "org.freedesktop.network1.Link",
907 properties);
908 }
909
link_send_changed(Link * link,const char * property,...)910 int link_send_changed(Link *link, const char *property, ...) {
911 char **properties;
912
913 properties = strv_from_stdarg_alloca(property);
914
915 return link_send_changed_strv(link, properties);
916 }
917
918 const BusObjectImplementation link_object = {
919 "/org/freedesktop/network1/link",
920 "org.freedesktop.network1.Link",
921 .fallback_vtables = BUS_FALLBACK_VTABLES({link_vtable, link_object_find}),
922 .node_enumerator = link_node_enumerator,
923 };
924