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