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