1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
2 
3 #include <linux/nexthop.h>
4 
5 #include "dns-domain.h"
6 #include "ip-protocol-list.h"
7 #include "netif-util.h"
8 #include "networkd-address.h"
9 #include "networkd-json.h"
10 #include "networkd-link.h"
11 #include "networkd-manager.h"
12 #include "networkd-neighbor.h"
13 #include "networkd-nexthop.h"
14 #include "networkd-network.h"
15 #include "networkd-route-util.h"
16 #include "networkd-route.h"
17 #include "networkd-routing-policy-rule.h"
18 #include "sort-util.h"
19 #include "user-util.h"
20 #include "wifi-util.h"
21 
address_build_json(Address * address,JsonVariant ** ret)22 static int address_build_json(Address *address, JsonVariant **ret) {
23         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
24         _cleanup_free_ char *scope = NULL, *flags = NULL, *state = NULL;
25         int r;
26 
27         assert(address);
28         assert(ret);
29 
30         r = route_scope_to_string_alloc(address->scope, &scope);
31         if (r < 0)
32                 return r;
33 
34         r = address_flags_to_string_alloc(address->flags, address->family, &flags);
35         if (r < 0)
36                 return r;
37 
38         r = network_config_state_to_string_alloc(address->state, &state);
39         if (r < 0)
40                 return r;
41 
42         r = json_build(&v, JSON_BUILD_OBJECT(
43                                 JSON_BUILD_PAIR_INTEGER("Family", address->family),
44                                 JSON_BUILD_PAIR_IN_ADDR("Address", &address->in_addr, address->family),
45                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Peer", &address->in_addr_peer, address->family),
46                                 JSON_BUILD_PAIR_IN4_ADDR_NON_NULL("Broadcast", &address->broadcast),
47                                 JSON_BUILD_PAIR_UNSIGNED("PrefixLength", address->prefixlen),
48                                 JSON_BUILD_PAIR_UNSIGNED("Scope", address->scope),
49                                 JSON_BUILD_PAIR_STRING("ScopeString", scope),
50                                 JSON_BUILD_PAIR_UNSIGNED("Flags", address->flags),
51                                 JSON_BUILD_PAIR_STRING("FlagsString", flags),
52                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Label", address->label),
53                                 JSON_BUILD_PAIR_FINITE_USEC("PreferredLifetimeUsec", address->lifetime_preferred_usec),
54                                 JSON_BUILD_PAIR_FINITE_USEC("ValidLifetimeUsec", address->lifetime_valid_usec),
55                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(address->source)),
56                                 JSON_BUILD_PAIR_STRING("ConfigState", state),
57                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &address->provider, address->family)));
58         if (r < 0)
59                 return r;
60 
61         *ret = TAKE_PTR(v);
62         return 0;
63 }
64 
addresses_build_json(Set * addresses,JsonVariant ** ret)65 static int addresses_build_json(Set *addresses, JsonVariant **ret) {
66         JsonVariant **elements;
67         Address *address;
68         size_t n = 0;
69         int r;
70 
71         assert(ret);
72 
73         if (set_isempty(addresses)) {
74                 *ret = NULL;
75                 return 0;
76         }
77 
78         elements = new(JsonVariant*, set_size(addresses));
79         if (!elements)
80                 return -ENOMEM;
81 
82         SET_FOREACH(address, addresses) {
83                 r = address_build_json(address, elements + n);
84                 if (r < 0)
85                         goto finalize;
86                 n++;
87         }
88 
89         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Addresses", JSON_BUILD_VARIANT_ARRAY(elements, n))));
90 
91 finalize:
92         json_variant_unref_many(elements, n);
93         free(elements);
94         return r;
95 }
96 
neighbor_build_json(Neighbor * n,JsonVariant ** ret)97 static int neighbor_build_json(Neighbor *n, JsonVariant **ret) {
98         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
99         _cleanup_free_ char *state = NULL;
100         int r;
101 
102         assert(n);
103         assert(ret);
104 
105         r = network_config_state_to_string_alloc(n->state, &state);
106         if (r < 0)
107                 return r;
108 
109         r = json_build(&v, JSON_BUILD_OBJECT(
110                                 JSON_BUILD_PAIR_INTEGER("Family", n->family),
111                                 JSON_BUILD_PAIR_IN_ADDR("Destination", &n->in_addr, n->family),
112                                 JSON_BUILD_PAIR_HW_ADDR("LinkLayerAddress", &n->ll_addr),
113                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
114                                 JSON_BUILD_PAIR_STRING("ConfigState", state)));
115         if (r < 0)
116                 return r;
117 
118         *ret = TAKE_PTR(v);
119         return 0;
120 }
121 
neighbors_build_json(Set * neighbors,JsonVariant ** ret)122 static int neighbors_build_json(Set *neighbors, JsonVariant **ret) {
123         JsonVariant **elements;
124         Neighbor *neighbor;
125         size_t n = 0;
126         int r;
127 
128         assert(ret);
129 
130         if (set_isempty(neighbors)) {
131                 *ret = NULL;
132                 return 0;
133         }
134 
135         elements = new(JsonVariant*, set_size(neighbors));
136         if (!elements)
137                 return -ENOMEM;
138 
139         SET_FOREACH(neighbor, neighbors) {
140                 r = neighbor_build_json(neighbor, elements + n);
141                 if (r < 0)
142                         goto finalize;
143                 n++;
144         }
145 
146         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Neighbors", JSON_BUILD_VARIANT_ARRAY(elements, n))));
147 
148 finalize:
149         json_variant_unref_many(elements, n);
150         free(elements);
151         return r;
152 }
153 
nexthop_group_build_json(NextHop * nexthop,JsonVariant ** ret)154 static int nexthop_group_build_json(NextHop *nexthop, JsonVariant **ret) {
155         JsonVariant **elements;
156         struct nexthop_grp *g;
157         size_t n = 0;
158         int r;
159 
160         assert(nexthop);
161         assert(ret);
162 
163         if (hashmap_isempty(nexthop->group)) {
164                 *ret = NULL;
165                 return 0;
166         }
167 
168         elements = new(JsonVariant*, hashmap_size(nexthop->group));
169         if (!elements)
170                 return -ENOMEM;
171 
172         HASHMAP_FOREACH(g, nexthop->group) {
173                 r = json_build(elements + n, JSON_BUILD_OBJECT(
174                                         JSON_BUILD_PAIR_UNSIGNED("ID", g->id),
175                                         JSON_BUILD_PAIR_UNSIGNED("Weight", g->weight+1)));
176                 if (r < 0)
177                         goto failure;
178 
179                 n++;
180         }
181 
182         r = json_variant_new_array(ret, elements, n);
183 
184 failure:
185         json_variant_unref_many(elements, n);
186         free(elements);
187         return r;
188 }
189 
nexthop_build_json(NextHop * n,JsonVariant ** ret)190 static int nexthop_build_json(NextHop *n, JsonVariant **ret) {
191         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *group = NULL;
192         _cleanup_free_ char *flags = NULL, *protocol = NULL, *state = NULL;
193         int r;
194 
195         assert(n);
196         assert(ret);
197 
198         r = route_flags_to_string_alloc(n->flags, &flags);
199         if (r < 0)
200                 return r;
201 
202         r = route_protocol_to_string_alloc(n->protocol, &protocol);
203         if (r < 0)
204                 return r;
205 
206         r = network_config_state_to_string_alloc(n->state, &state);
207         if (r < 0)
208                 return r;
209 
210         r = nexthop_group_build_json(n, &group);
211         if (r < 0)
212                 return r;
213 
214         r = json_build(&v, JSON_BUILD_OBJECT(
215                                 JSON_BUILD_PAIR_UNSIGNED("ID", n->id),
216                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &n->gw, n->family),
217                                 JSON_BUILD_PAIR_UNSIGNED("Flags", n->flags),
218                                 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
219                                 JSON_BUILD_PAIR_UNSIGNED("Protocol", n->protocol),
220                                 JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
221                                 JSON_BUILD_PAIR_BOOLEAN("Blackhole", n->blackhole),
222                                 JSON_BUILD_PAIR_VARIANT_NON_NULL("Group", group),
223                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(n->source)),
224                                 JSON_BUILD_PAIR_STRING("ConfigState", state)));
225         if (r < 0)
226                 return r;
227 
228         *ret = TAKE_PTR(v);
229         return 0;
230 }
231 
nexthops_build_json(Set * nexthops,JsonVariant ** ret)232 static int nexthops_build_json(Set *nexthops, JsonVariant **ret) {
233         JsonVariant **elements;
234         NextHop *nexthop;
235         size_t n = 0;
236         int r;
237 
238         assert(ret);
239 
240         if (set_isempty(nexthops)) {
241                 *ret = NULL;
242                 return 0;
243         }
244 
245         elements = new(JsonVariant*, set_size(nexthops));
246         if (!elements)
247                 return -ENOMEM;
248 
249         SET_FOREACH(nexthop, nexthops) {
250                 r = nexthop_build_json(nexthop, elements + n);
251                 if (r < 0)
252                         goto finalize;
253                 n++;
254         }
255 
256         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("NextHops", JSON_BUILD_VARIANT_ARRAY(elements, n))));
257 
258 finalize:
259         json_variant_unref_many(elements, n);
260         free(elements);
261         return r;
262 }
263 
route_build_json(Route * route,JsonVariant ** ret)264 static int route_build_json(Route *route, JsonVariant **ret) {
265         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
266         _cleanup_free_ char *scope = NULL, *protocol = NULL, *table = NULL, *flags = NULL, *state = NULL;
267         Manager *manager;
268         int r;
269 
270         assert(route);
271         assert(ret);
272 
273         manager = route->link ? route->link->manager : route->manager;
274 
275         assert(manager);
276 
277         r = route_scope_to_string_alloc(route->scope, &scope);
278         if (r < 0)
279                 return r;
280 
281         r = route_protocol_to_string_alloc(route->protocol, &protocol);
282         if (r < 0)
283                 return r;
284 
285         r = manager_get_route_table_to_string(manager, route->table, &table);
286         if (r < 0)
287                 return r;
288 
289         r = route_flags_to_string_alloc(route->flags, &flags);
290         if (r < 0)
291                 return r;
292 
293         r = network_config_state_to_string_alloc(route->state, &state);
294         if (r < 0)
295                 return r;
296 
297         r = json_build(&v, JSON_BUILD_OBJECT(
298                                 JSON_BUILD_PAIR_INTEGER("Family", route->family),
299                                 JSON_BUILD_PAIR_IN_ADDR("Destination", &route->dst, route->family),
300                                 JSON_BUILD_PAIR_UNSIGNED("DestinationPrefixLength", route->dst_prefixlen),
301                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("Gateway", &route->gw, route->gw_family),
302                                 JSON_BUILD_PAIR_CONDITION(route->src_prefixlen > 0,
303                                                           "Source", JSON_BUILD_IN_ADDR(&route->src, route->family)),
304                                 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("SourcePrefixLength", route->src_prefixlen),
305                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("PreferredSource", &route->prefsrc, route->family),
306                                 JSON_BUILD_PAIR_UNSIGNED("Scope", route->scope),
307                                 JSON_BUILD_PAIR_STRING("ScopeString", scope),
308                                 JSON_BUILD_PAIR_UNSIGNED("Protocol", route->protocol),
309                                 JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
310                                 JSON_BUILD_PAIR_UNSIGNED("Type", route->type),
311                                 JSON_BUILD_PAIR_STRING("TypeString", route_type_to_string(route->type)),
312                                 JSON_BUILD_PAIR_UNSIGNED("Priority", route->priority),
313                                 JSON_BUILD_PAIR_UNSIGNED("Table", route->table),
314                                 JSON_BUILD_PAIR_STRING("TableString", table),
315                                 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("MTU", route->mtu),
316                                 JSON_BUILD_PAIR_UNSIGNED("Preference", route->pref),
317                                 JSON_BUILD_PAIR_UNSIGNED("Flags", route->flags),
318                                 JSON_BUILD_PAIR_STRING("FlagsString", strempty(flags)),
319                                 JSON_BUILD_PAIR_FINITE_USEC("LifetimeUSec", route->lifetime_usec),
320                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(route->source)),
321                                 JSON_BUILD_PAIR_STRING("ConfigState", state),
322                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", &route->provider, route->family)));
323         if (r < 0)
324                 return r;
325 
326         *ret = TAKE_PTR(v);
327         return 0;
328 }
329 
routes_build_json(Set * routes,JsonVariant ** ret)330 static int routes_build_json(Set *routes, JsonVariant **ret) {
331         JsonVariant **elements;
332         Route *route;
333         size_t n = 0;
334         int r;
335 
336         assert(ret);
337 
338         if (set_isempty(routes)) {
339                 *ret = NULL;
340                 return 0;
341         }
342 
343         elements = new(JsonVariant*, set_size(routes));
344         if (!elements)
345                 return -ENOMEM;
346 
347         SET_FOREACH(route, routes) {
348                 r = route_build_json(route, elements + n);
349                 if (r < 0)
350                         goto finalize;
351                 n++;
352         }
353 
354         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Routes", JSON_BUILD_VARIANT_ARRAY(elements, n))));
355 
356 finalize:
357         json_variant_unref_many(elements, n);
358         free(elements);
359         return r;
360 }
361 
routing_policy_rule_build_json(RoutingPolicyRule * rule,JsonVariant ** ret)362 static int routing_policy_rule_build_json(RoutingPolicyRule *rule, JsonVariant **ret) {
363         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
364         _cleanup_free_ char *table = NULL, *protocol = NULL, *state = NULL;
365         int r;
366 
367         assert(rule);
368         assert(rule->manager);
369         assert(ret);
370 
371         r = manager_get_route_table_to_string(rule->manager, rule->table, &table);
372         if (r < 0 && r != -EINVAL)
373                 return r;
374 
375         r = route_protocol_to_string_alloc(rule->protocol, &protocol);
376         if (r < 0)
377                 return r;
378 
379         r = network_config_state_to_string_alloc(rule->state, &state);
380         if (r < 0)
381                 return r;
382 
383         r = json_build(&v, JSON_BUILD_OBJECT(
384                                 JSON_BUILD_PAIR_INTEGER("Family", rule->family),
385                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("FromPrefix", &rule->from, rule->family),
386                                 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule->family, &rule->from),
387                                                           "FromPrefixLength", JSON_BUILD_UNSIGNED(rule->from_prefixlen)),
388                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ToPrefix", &rule->to, rule->family),
389                                 JSON_BUILD_PAIR_CONDITION(in_addr_is_set(rule->family, &rule->to),
390                                                           "ToPrefixLength", JSON_BUILD_UNSIGNED(rule->to_prefixlen)),
391                                 JSON_BUILD_PAIR_UNSIGNED("Protocol", rule->protocol),
392                                 JSON_BUILD_PAIR_STRING("ProtocolString", protocol),
393                                 JSON_BUILD_PAIR_UNSIGNED("TOS", rule->tos),
394                                 JSON_BUILD_PAIR_UNSIGNED("Type", rule->type),
395                                 JSON_BUILD_PAIR_STRING("TypeString", fr_act_type_full_to_string(rule->type)),
396                                 JSON_BUILD_PAIR_UNSIGNED("IPProtocol", rule->ipproto),
397                                 JSON_BUILD_PAIR_STRING("IPProtocolString", ip_protocol_to_name(rule->ipproto)),
398                                 JSON_BUILD_PAIR_UNSIGNED("Priority", rule->priority),
399                                 JSON_BUILD_PAIR_UNSIGNED("FirewallMark", rule->fwmark),
400                                 JSON_BUILD_PAIR_UNSIGNED("FirewallMask", rule->fwmask),
401                                 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Table", rule->table),
402                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("TableString", table),
403                                 JSON_BUILD_PAIR_BOOLEAN("Invert", rule->invert_rule),
404                                 JSON_BUILD_PAIR_CONDITION(rule->suppress_prefixlen >= 0,
405                                                           "SuppressPrefixLength", JSON_BUILD_UNSIGNED(rule->suppress_prefixlen)),
406                                 JSON_BUILD_PAIR_CONDITION(rule->suppress_ifgroup >= 0,
407                                                           "SuppressInterfaceGroup", JSON_BUILD_UNSIGNED(rule->suppress_ifgroup)),
408                                 JSON_BUILD_PAIR_CONDITION(rule->sport.start != 0 || rule->sport.end != 0, "SourcePort",
409                                                           JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->sport.start), JSON_BUILD_UNSIGNED(rule->sport.end))),
410                                 JSON_BUILD_PAIR_CONDITION(rule->dport.start != 0 || rule->dport.end != 0, "DestinationPort",
411                                                           JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->dport.start), JSON_BUILD_UNSIGNED(rule->dport.end))),
412                                 JSON_BUILD_PAIR_CONDITION(rule->uid_range.start != UID_INVALID && rule->uid_range.end != UID_INVALID, "User",
413                                                           JSON_BUILD_ARRAY(JSON_BUILD_UNSIGNED(rule->uid_range.start), JSON_BUILD_UNSIGNED(rule->uid_range.end))),
414                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("IncomingInterface", rule->iif),
415                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("OutgoingInterface", rule->oif),
416                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(rule->source)),
417                                 JSON_BUILD_PAIR_STRING("ConfigState", state)));
418         if (r < 0)
419                 return r;
420 
421         *ret = TAKE_PTR(v);
422         return 0;
423 }
424 
routing_policy_rules_build_json(Set * rules,JsonVariant ** ret)425 static int routing_policy_rules_build_json(Set *rules, JsonVariant **ret) {
426         JsonVariant **elements;
427         RoutingPolicyRule *rule;
428         size_t n = 0;
429         int r;
430 
431         assert(ret);
432 
433         if (set_isempty(rules)) {
434                 *ret = NULL;
435                 return 0;
436         }
437 
438         elements = new(JsonVariant*, set_size(rules));
439         if (!elements)
440                 return -ENOMEM;
441 
442         SET_FOREACH(rule, rules) {
443                 r = routing_policy_rule_build_json(rule, elements + n);
444                 if (r < 0)
445                         goto finalize;
446                 n++;
447         }
448 
449         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("RoutingPolicyRules", JSON_BUILD_VARIANT_ARRAY(elements, n))));
450 
451 finalize:
452         json_variant_unref_many(elements, n);
453         free(elements);
454         return r;
455 }
456 
network_build_json(Network * network,JsonVariant ** ret)457 static int network_build_json(Network *network, JsonVariant **ret) {
458         assert(ret);
459 
460         if (!network) {
461                 *ret = NULL;
462                 return 0;
463         }
464 
465         return json_build(ret, JSON_BUILD_OBJECT(
466                                 JSON_BUILD_PAIR_STRING("NetworkFile", network->filename),
467                                 JSON_BUILD_PAIR_BOOLEAN("RequiredForOnline", network->required_for_online),
468                                 JSON_BUILD_PAIR("RequiredOperationalStateForOnline",
469                                                 JSON_BUILD_ARRAY(JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.min)),
470                                                                  JSON_BUILD_STRING(link_operstate_to_string(network->required_operstate_for_online.max)))),
471                                 JSON_BUILD_PAIR_STRING("RequiredFamilyForOnline",
472                                                        link_required_address_family_to_string(network->required_family_for_online)),
473                                 JSON_BUILD_PAIR_STRING("ActivationPolicy",
474                                                        activation_policy_to_string(network->activation_policy))));
475 }
476 
device_build_json(sd_device * device,JsonVariant ** ret)477 static int device_build_json(sd_device *device, JsonVariant **ret) {
478         const char *link = NULL, *path = NULL, *vendor = NULL, *model = NULL;
479 
480         assert(ret);
481 
482         if (!device) {
483                 *ret = NULL;
484                 return 0;
485         }
486 
487         (void) sd_device_get_property_value(device, "ID_NET_LINK_FILE", &link);
488         (void) sd_device_get_property_value(device, "ID_PATH", &path);
489 
490         if (sd_device_get_property_value(device, "ID_VENDOR_FROM_DATABASE", &vendor) < 0)
491                 (void) sd_device_get_property_value(device, "ID_VENDOR", &vendor);
492 
493         if (sd_device_get_property_value(device, "ID_MODEL_FROM_DATABASE", &model) < 0)
494                 (void) sd_device_get_property_value(device, "ID_MODEL", &model);
495 
496         return json_build(ret, JSON_BUILD_OBJECT(
497                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("LinkFile", link),
498                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Path", path),
499                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Vendor", vendor),
500                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Model", model)));
501 }
502 
dns_build_json_one(Link * link,const struct in_addr_full * a,NetworkConfigSource s,const union in_addr_union * p,JsonVariant ** ret)503 static int dns_build_json_one(Link *link, const struct in_addr_full *a, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **ret) {
504         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL;
505         int r;
506 
507         assert(link);
508         assert(a);
509         assert(ret);
510 
511         if (a->ifindex != 0 && a->ifindex != link->ifindex) {
512                 *ret = NULL;
513                 return 0;
514         }
515 
516         r = json_build(&v, JSON_BUILD_OBJECT(
517                                 JSON_BUILD_PAIR_INTEGER("Family", a->family),
518                                 JSON_BUILD_PAIR_IN_ADDR("Address", &a->address, a->family),
519                                 JSON_BUILD_PAIR_UNSIGNED_NON_ZERO("Port", a->port),
520                                 JSON_BUILD_PAIR_CONDITION(a->ifindex != 0, "InterfaceIndex", JSON_BUILD_INTEGER(a->ifindex)),
521                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("ServerName", a->server_name),
522                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
523                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, a->family)));
524         if (r < 0)
525                 return r;
526 
527         *ret = TAKE_PTR(v);
528         return 1;
529 }
530 
dns_build_json(Link * link,JsonVariant ** ret)531 static int dns_build_json(Link *link, JsonVariant **ret) {
532         JsonVariant **elements = NULL;
533         size_t n = 0;
534         int r;
535 
536         assert(link);
537         assert(ret);
538 
539         if (!link->network) {
540                 *ret = NULL;
541                 return 0;
542         }
543 
544         if (link->n_dns != UINT_MAX) {
545                 for (unsigned i = 0; i < link->n_dns; i++) {
546                         if (!GREEDY_REALLOC(elements, n + 1)) {
547                                 r = -ENOMEM;
548                                 goto finalize;
549                         }
550 
551                         r = dns_build_json_one(link, link->dns[i], NETWORK_CONFIG_SOURCE_RUNTIME, NULL, elements + n);
552                         if (r < 0)
553                                 goto finalize;
554                         if (r > 0)
555                                 n++;
556                 }
557         } else {
558                 for (unsigned i = 0; i < link->network->n_dns; i++) {
559                         if (!GREEDY_REALLOC(elements, n + 1)) {
560                                 r = -ENOMEM;
561                                 goto finalize;
562                         }
563 
564                         r = dns_build_json_one(link, link->network->dns[i], NETWORK_CONFIG_SOURCE_STATIC, NULL, elements + n);
565                         if (r < 0)
566                                 goto finalize;
567                         if (r > 0)
568                                 n++;
569                 }
570 
571                 if (link->dhcp_lease && link->network->dhcp_use_dns) {
572                         const struct in_addr *dns;
573                         union in_addr_union s;
574                         int n_dns;
575 
576                         r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &s.in);
577                         if (r < 0)
578                                 goto finalize;
579 
580                         n_dns = sd_dhcp_lease_get_dns(link->dhcp_lease, &dns);
581                         for (int i = 0; i < n_dns; i++) {
582                                 if (!GREEDY_REALLOC(elements, n + 1)) {
583                                         r = -ENOMEM;
584                                         goto finalize;
585                                 }
586 
587                                 r = dns_build_json_one(link,
588                                                        &(struct in_addr_full) { .family = AF_INET, .address.in = dns[i], },
589                                                        NETWORK_CONFIG_SOURCE_DHCP4,
590                                                        &s,
591                                                        elements + n);
592                                 if (r < 0)
593                                         goto finalize;
594                                 if (r > 0)
595                                         n++;
596                         }
597                 }
598 
599                 if (link->dhcp6_lease && link->network->dhcp6_use_dns) {
600                         const struct in6_addr *dns;
601                         union in_addr_union s;
602                         int n_dns;
603 
604                         r = sd_dhcp6_lease_get_server_address(link->dhcp6_lease, &s.in6);
605                         if (r < 0)
606                                 goto finalize;
607 
608                         n_dns = sd_dhcp6_lease_get_dns(link->dhcp6_lease, &dns);
609                         for (int i = 0; i < n_dns; i++) {
610                                 if (!GREEDY_REALLOC(elements, n + 1)) {
611                                         r = -ENOMEM;
612                                         goto finalize;
613                                 }
614 
615                                 r = dns_build_json_one(link,
616                                                        &(struct in_addr_full) { .family = AF_INET6, .address.in6 = dns[i], },
617                                                        NETWORK_CONFIG_SOURCE_DHCP6,
618                                                        &s,
619                                                        elements + n);
620                                 if (r < 0)
621                                         goto finalize;
622                                 if (r > 0)
623                                         n++;
624                         }
625                 }
626 
627                 if (link->network->ipv6_accept_ra_use_dns) {
628                         NDiscRDNSS *a;
629 
630                         SET_FOREACH(a, link->ndisc_rdnss) {
631                                 if (!GREEDY_REALLOC(elements, n + 1)) {
632                                         r = -ENOMEM;
633                                         goto finalize;
634                                 }
635 
636                                 r = dns_build_json_one(link,
637                                                        &(struct in_addr_full) { .family = AF_INET6, .address.in6 = a->address, },
638                                                        NETWORK_CONFIG_SOURCE_NDISC,
639                                                        &(union in_addr_union) { .in6 = a->router },
640                                                        elements + n);
641                                 if (r < 0)
642                                         goto finalize;
643                                 if (r > 0)
644                                         n++;
645                         }
646                 }
647         }
648 
649         if (n == 0) {
650                 *ret = NULL;
651                 r = 0;
652                 goto finalize;
653         }
654 
655         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("DNS", JSON_BUILD_VARIANT_ARRAY(elements, n))));
656 
657 finalize:
658         json_variant_unref_many(elements, n);
659         free(elements);
660         return r;
661 }
662 
server_build_json_one_addr(int family,const union in_addr_union * a,NetworkConfigSource s,const union in_addr_union * p,JsonVariant ** ret)663 static int server_build_json_one_addr(int family, const union in_addr_union *a, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **ret) {
664         assert(IN_SET(family, AF_INET, AF_INET6));
665         assert(a);
666         assert(ret);
667 
668         return json_build(ret, JSON_BUILD_OBJECT(
669                                 JSON_BUILD_PAIR_INTEGER("Family", family),
670                                 JSON_BUILD_PAIR_IN_ADDR("Address", a, family),
671                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
672                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, family)));
673 }
674 
server_build_json_one_fqdn(int family,const char * fqdn,NetworkConfigSource s,const union in_addr_union * p,JsonVariant ** ret)675 static int server_build_json_one_fqdn(int family, const char *fqdn, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **ret) {
676         assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
677         assert(fqdn);
678         assert(ret);
679 
680         return json_build(ret, JSON_BUILD_OBJECT(
681                                 JSON_BUILD_PAIR_STRING("Server", fqdn),
682                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
683                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, family)));
684 }
685 
server_build_json_one_string(const char * str,NetworkConfigSource s,JsonVariant ** ret)686 static int server_build_json_one_string(const char *str, NetworkConfigSource s, JsonVariant **ret) {
687         union in_addr_union a;
688         int family;
689 
690         assert(str);
691         assert(ret);
692 
693         if (in_addr_from_string_auto(str, &family, &a) >= 0)
694                 return server_build_json_one_addr(family, &a, s, NULL, ret);
695 
696         return server_build_json_one_fqdn(AF_UNSPEC, str, s, NULL, ret);
697 }
698 
ntp_build_json(Link * link,JsonVariant ** ret)699 static int ntp_build_json(Link *link, JsonVariant **ret) {
700         JsonVariant **elements = NULL;
701         size_t n = 0;
702         int r;
703 
704         assert(link);
705         assert(ret);
706 
707         if (!link->network) {
708                 *ret = NULL;
709                 return 0;
710         }
711 
712         STRV_FOREACH(p, link->ntp ?: link->network->ntp) {
713                 if (!GREEDY_REALLOC(elements, n + 1)) {
714                         r = -ENOMEM;
715                         goto finalize;
716                 }
717 
718                 r = server_build_json_one_string(*p, NETWORK_CONFIG_SOURCE_RUNTIME, elements + n);
719                 if (r < 0)
720                         goto finalize;
721 
722                 n++;
723         }
724 
725         if (!link->ntp) {
726                 if (link->dhcp_lease && link->network->dhcp_use_ntp) {
727                         const struct in_addr *ntp;
728                         union in_addr_union s;
729                         int n_ntp;
730 
731                         r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &s.in);
732                         if (r < 0)
733                                 goto finalize;
734 
735                         n_ntp = sd_dhcp_lease_get_ntp(link->dhcp_lease, &ntp);
736                         for (int i = 0; i < n_ntp; i++) {
737                                 if (!GREEDY_REALLOC(elements, n + 1)) {
738                                         r = -ENOMEM;
739                                         goto finalize;
740                                 }
741 
742                                 r = server_build_json_one_addr(AF_INET,
743                                                                &(union in_addr_union) { .in = ntp[i], },
744                                                                NETWORK_CONFIG_SOURCE_DHCP4,
745                                                                &s,
746                                                                elements + n);
747                                 if (r < 0)
748                                         goto finalize;
749 
750                                 n++;
751                         }
752                 }
753 
754                 if (link->dhcp6_lease && link->network->dhcp6_use_ntp) {
755                         const struct in6_addr *ntp_addr;
756                         union in_addr_union s;
757                         char **ntp_fqdn;
758                         int n_ntp;
759 
760                         r = sd_dhcp6_lease_get_server_address(link->dhcp6_lease, &s.in6);
761                         if (r < 0)
762                                 goto finalize;
763 
764                         n_ntp = sd_dhcp6_lease_get_ntp_addrs(link->dhcp6_lease, &ntp_addr);
765                         for (int i = 0; i < n_ntp; i++) {
766                                 if (!GREEDY_REALLOC(elements, n + 1)) {
767                                         r = -ENOMEM;
768                                         goto finalize;
769                                 }
770 
771                                 r = server_build_json_one_addr(AF_INET6,
772                                                                &(union in_addr_union) { .in6 = ntp_addr[i], },
773                                                                NETWORK_CONFIG_SOURCE_DHCP6,
774                                                                &s,
775                                                                elements + n);
776                                 if (r < 0)
777                                         goto finalize;
778 
779                                 n++;
780                         }
781 
782                         n_ntp = sd_dhcp6_lease_get_ntp_fqdn(link->dhcp6_lease, &ntp_fqdn);
783                         for (int i = 0; i < n_ntp; i++) {
784                                 if (!GREEDY_REALLOC(elements, n + 1)) {
785                                         r = -ENOMEM;
786                                         goto finalize;
787                                 }
788 
789                                 r = server_build_json_one_fqdn(AF_INET6,
790                                                                ntp_fqdn[i],
791                                                                NETWORK_CONFIG_SOURCE_DHCP6,
792                                                                &s,
793                                                                elements + n);
794                                 if (r < 0)
795                                         goto finalize;
796 
797                                 n++;
798                         }
799                 }
800         }
801 
802         if (n == 0) {
803                 *ret = NULL;
804                 return 0;
805         }
806 
807         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("NTP", JSON_BUILD_VARIANT_ARRAY(elements, n))));
808 
809 finalize:
810         json_variant_unref_many(elements, n);
811         free(elements);
812         return r;
813 }
814 
sip_build_json(Link * link,JsonVariant ** ret)815 static int sip_build_json(Link *link, JsonVariant **ret) {
816         const struct in_addr *sip;
817         JsonVariant **elements;
818         union in_addr_union s;
819         size_t n = 0;
820         int n_sip, r;
821 
822         assert(link);
823         assert(ret);
824 
825         if (!link->network || !link->network->dhcp_use_sip || !link->dhcp_lease) {
826                 *ret = NULL;
827                 return 0;
828         }
829 
830         n_sip = sd_dhcp_lease_get_sip(link->dhcp_lease, &sip);
831         if (n_sip <= 0) {
832                 *ret = NULL;
833                 return 0;
834         }
835 
836         r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &s.in);
837         if (r < 0)
838                 return r;
839 
840         elements = new(JsonVariant*, n_sip);
841         if (!elements)
842                 return -ENOMEM;
843 
844         for (int i = 0; i < n_sip; i++) {
845                 r = server_build_json_one_addr(AF_INET,
846                                                &(union in_addr_union) { .in = sip[i], },
847                                                NETWORK_CONFIG_SOURCE_DHCP4,
848                                                &s,
849                                                elements + n);
850                 if (r < 0)
851                         goto finalize;
852                 if (r > 0)
853                         n++;
854         }
855 
856         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("SIP", JSON_BUILD_VARIANT_ARRAY(elements, n))));
857 
858 finalize:
859         json_variant_unref_many(elements, n);
860         free(elements);
861         return r;
862 }
863 
domain_build_json(int family,const char * domain,NetworkConfigSource s,const union in_addr_union * p,JsonVariant ** ret)864 static int domain_build_json(int family, const char *domain, NetworkConfigSource s, const union in_addr_union *p, JsonVariant **ret) {
865         assert(IN_SET(family, AF_UNSPEC, AF_INET, AF_INET6));
866         assert(domain);
867         assert(ret);
868 
869         return json_build(ret, JSON_BUILD_OBJECT(
870                                 JSON_BUILD_PAIR_STRING("Domain", domain),
871                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s)),
872                                 JSON_BUILD_PAIR_IN_ADDR_NON_NULL("ConfigProvider", p, family)));
873 }
874 
domains_build_json(Link * link,bool is_route,JsonVariant ** ret)875 static int domains_build_json(Link *link, bool is_route, JsonVariant **ret) {
876         OrderedSet *link_domains, *network_domains;
877         JsonVariant **elements = NULL;
878         DHCPUseDomains use_domains;
879         union in_addr_union s;
880         char **domains;
881         const char *domain;
882         size_t n = 0;
883         int r;
884 
885         assert(link);
886         assert(ret);
887 
888         if (!link->network) {
889                 *ret = NULL;
890                 return 0;
891         }
892 
893         link_domains = is_route ? link->route_domains : link->search_domains;
894         network_domains = is_route ? link->network->route_domains : link->network->search_domains;
895         use_domains = is_route ? DHCP_USE_DOMAINS_ROUTE : DHCP_USE_DOMAINS_YES;
896 
897         ORDERED_SET_FOREACH(domain, link_domains ?: network_domains) {
898                 if (!GREEDY_REALLOC(elements, n + 1)) {
899                         r = -ENOMEM;
900                         goto finalize;
901                 }
902 
903                 r = domain_build_json(AF_UNSPEC, domain,
904                                       link_domains ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC,
905                                       NULL, elements + n);
906                 if (r < 0)
907                         goto finalize;
908 
909                 n++;
910         }
911 
912         if (!link_domains) {
913                 if (link->dhcp_lease &&
914                     link->network->dhcp_use_domains == use_domains) {
915                         r = sd_dhcp_lease_get_server_identifier(link->dhcp_lease, &s.in);
916                         if (r < 0)
917                                 goto finalize;
918 
919                         if (sd_dhcp_lease_get_domainname(link->dhcp_lease, &domain) >= 0) {
920                                 if (!GREEDY_REALLOC(elements, n + 1)) {
921                                         r = -ENOMEM;
922                                         goto finalize;
923                                 }
924 
925                                 r = domain_build_json(AF_INET, domain, NETWORK_CONFIG_SOURCE_DHCP4, &s, elements + n);
926                                 if (r < 0)
927                                         goto finalize;
928 
929                                 n++;
930                         }
931 
932                         if (sd_dhcp_lease_get_search_domains(link->dhcp_lease, &domains) >= 0) {
933                                 STRV_FOREACH(p, domains) {
934                                         if (!GREEDY_REALLOC(elements, n + 1)) {
935                                                 r = -ENOMEM;
936                                                 goto finalize;
937                                         }
938 
939                                         r = domain_build_json(AF_INET, *p, NETWORK_CONFIG_SOURCE_DHCP4, &s, elements + n);
940                                         if (r < 0)
941                                                 goto finalize;
942 
943                                         n++;
944                                 }
945                         }
946                 }
947 
948                 if (link->dhcp6_lease &&
949                     link->network->dhcp6_use_domains == use_domains) {
950                         r = sd_dhcp6_lease_get_server_address(link->dhcp6_lease, &s.in6);
951                         if (r < 0)
952                                 goto finalize;
953 
954                         if (sd_dhcp6_lease_get_domains(link->dhcp6_lease, &domains) >= 0) {
955                                 STRV_FOREACH(p, domains) {
956                                         if (!GREEDY_REALLOC(elements, n + 1)) {
957                                                 r = -ENOMEM;
958                                                 goto finalize;
959                                         }
960 
961                                         r = domain_build_json(AF_INET6, *p, NETWORK_CONFIG_SOURCE_DHCP6, &s, elements + n);
962                                         if (r < 0)
963                                                 goto finalize;
964 
965                                         n++;
966                                 }
967                         }
968                 }
969 
970                 if (link->network->ipv6_accept_ra_use_domains == use_domains) {
971                         NDiscDNSSL *a;
972 
973                         SET_FOREACH(a, link->ndisc_dnssl) {
974                                 if (!GREEDY_REALLOC(elements, n + 1)) {
975                                         r = -ENOMEM;
976                                         goto finalize;
977                                 }
978 
979                                 r = domain_build_json(AF_INET6, NDISC_DNSSL_DOMAIN(a), NETWORK_CONFIG_SOURCE_NDISC,
980                                                       &(union in_addr_union) { .in6 = a->router },
981                                                       elements + n);
982                                 if (r < 0)
983                                         goto finalize;
984 
985                                 n++;
986                         }
987                 }
988         }
989 
990         if (n == 0) {
991                 *ret = NULL;
992                 return 0;
993         }
994 
995         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR(is_route ? "RouteDomains" : "SearchDomains",
996                                                               JSON_BUILD_VARIANT_ARRAY(elements, n))));
997 
998 finalize:
999         json_variant_unref_many(elements, n);
1000         free(elements);
1001         return r;
1002 }
1003 
nta_build_json(const char * nta,NetworkConfigSource s,JsonVariant ** ret)1004 static int nta_build_json(const char *nta, NetworkConfigSource s, JsonVariant **ret) {
1005         assert(nta);
1006         assert(ret);
1007 
1008         return json_build(ret, JSON_BUILD_OBJECT(
1009                                 JSON_BUILD_PAIR_STRING("DNSSECNegativeTrustAnchor", nta),
1010                                 JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(s))));
1011 }
1012 
ntas_build_json(Link * link,JsonVariant ** ret)1013 static int ntas_build_json(Link *link, JsonVariant **ret) {
1014         JsonVariant **elements = NULL;
1015         const char *nta;
1016         size_t n = 0;
1017         int r;
1018 
1019         assert(link);
1020         assert(ret);
1021 
1022         if (!link->network) {
1023                 *ret = NULL;
1024                 return 0;
1025         }
1026 
1027         SET_FOREACH(nta, link->dnssec_negative_trust_anchors ?: link->network->dnssec_negative_trust_anchors) {
1028                 if (!GREEDY_REALLOC(elements, n + 1)) {
1029                         r = -ENOMEM;
1030                         goto finalize;
1031                 }
1032 
1033                 r = nta_build_json(nta,
1034                                    link->dnssec_negative_trust_anchors ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC,
1035                                    elements + n);
1036                 if (r < 0)
1037                         goto finalize;
1038 
1039                 n++;
1040         }
1041 
1042         if (n == 0) {
1043                 *ret = NULL;
1044                 return 0;
1045         }
1046 
1047         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("DNSSECNegativeTrustAnchors",
1048                                                               JSON_BUILD_VARIANT_ARRAY(elements, n))));
1049 
1050 finalize:
1051         json_variant_unref_many(elements, n);
1052         free(elements);
1053         return r;
1054 }
1055 
dns_misc_build_json(Link * link,JsonVariant ** ret)1056 static int dns_misc_build_json(Link *link, JsonVariant **ret) {
1057         JsonVariant **elements = NULL;
1058         ResolveSupport resolve_support;
1059         NetworkConfigSource source;
1060         DnsOverTlsMode mode;
1061         size_t n = 0;
1062         int t, r;
1063 
1064         assert(link);
1065         assert(ret);
1066 
1067         if (!link->network) {
1068                 *ret = NULL;
1069                 return 0;
1070         }
1071 
1072         resolve_support = link->llmnr >= 0 ? link->llmnr : link->network->llmnr;
1073         if (resolve_support >= 0) {
1074                 source = link->llmnr >= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC;
1075 
1076                 if (!GREEDY_REALLOC(elements, n + 1)) {
1077                         r = -ENOMEM;
1078                         goto finalize;
1079                 }
1080 
1081                 r = json_build(elements + n, JSON_BUILD_OBJECT(
1082                                         JSON_BUILD_PAIR_STRING("LLMNR", resolve_support_to_string(resolve_support)),
1083                                         JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source))));
1084                 if (r < 0)
1085                         goto finalize;
1086 
1087                 n++;
1088         }
1089 
1090         resolve_support = link->mdns >= 0 ? link->mdns : link->network->mdns;
1091         if (resolve_support >= 0) {
1092                 source = link->mdns >= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC;
1093 
1094                 if (!GREEDY_REALLOC(elements, n + 1)) {
1095                         r = -ENOMEM;
1096                         goto finalize;
1097                 }
1098 
1099                 r = json_build(elements + n, JSON_BUILD_OBJECT(
1100                                         JSON_BUILD_PAIR_STRING("MDNS", resolve_support_to_string(resolve_support)),
1101                                         JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source))));
1102                 if (r < 0)
1103                         goto finalize;
1104 
1105                 n++;
1106         }
1107 
1108         t = link->dns_default_route >= 0 ? link->dns_default_route : link->network->dns_default_route;
1109         if (t >= 0) {
1110                 source = link->dns_default_route >= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC;
1111 
1112                 if (!GREEDY_REALLOC(elements, n + 1)) {
1113                         r = -ENOMEM;
1114                         goto finalize;
1115                 }
1116 
1117                 r = json_build(elements + n, JSON_BUILD_OBJECT(
1118                                         JSON_BUILD_PAIR_BOOLEAN("DNSDefaultRoute", t),
1119                                         JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source))));
1120                 if (r < 0)
1121                         goto finalize;
1122 
1123                 n++;
1124         }
1125 
1126         mode = link->dns_over_tls_mode >= 0 ? link->dns_over_tls_mode : link->network->dns_over_tls_mode;
1127         if (mode >= 0) {
1128                 source = link->dns_over_tls_mode >= 0 ? NETWORK_CONFIG_SOURCE_RUNTIME : NETWORK_CONFIG_SOURCE_STATIC;
1129 
1130                 if (!GREEDY_REALLOC(elements, n + 1)) {
1131                         r = -ENOMEM;
1132                         goto finalize;
1133                 }
1134 
1135                 r = json_build(elements + n, JSON_BUILD_OBJECT(
1136                                         JSON_BUILD_PAIR_STRING("DNSOverTLS", dns_over_tls_mode_to_string(mode)),
1137                                         JSON_BUILD_PAIR_STRING("ConfigSource", network_config_source_to_string(source))));
1138                 if (r < 0)
1139                         goto finalize;
1140 
1141                 n++;
1142         }
1143 
1144         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("DNSSettings",
1145                                                               JSON_BUILD_VARIANT_ARRAY(elements, n))));
1146 
1147 finalize:
1148         json_variant_unref_many(elements, n);
1149         free(elements);
1150         return r;
1151 }
1152 
link_build_json(Link * link,JsonVariant ** ret)1153 int link_build_json(Link *link, JsonVariant **ret) {
1154         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
1155         _cleanup_free_ char *type = NULL, *flags = NULL;
1156         int r;
1157 
1158         assert(link);
1159         assert(ret);
1160 
1161         r = net_get_type_string(link->sd_device, link->iftype, &type);
1162         if (r == -ENOMEM)
1163                 return r;
1164 
1165         r = link_flags_to_string_alloc(link->flags, &flags);
1166         if (r < 0)
1167                 return r;
1168 
1169         r = json_build(&v, JSON_BUILD_OBJECT(
1170                                 /* basic information */
1171                                 JSON_BUILD_PAIR_INTEGER("Index", link->ifindex),
1172                                 JSON_BUILD_PAIR_STRING("Name", link->ifname),
1173                                 JSON_BUILD_PAIR_STRV_NON_EMPTY("AlternativeNames", link->alternative_names),
1174                                 JSON_BUILD_PAIR_CONDITION(link->master_ifindex > 0,
1175                                                           "MasterInterfaceIndex", JSON_BUILD_INTEGER(link->master_ifindex)),
1176                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Kind", link->kind),
1177                                 JSON_BUILD_PAIR_STRING("Type", type),
1178                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("Driver", link->driver),
1179                                 JSON_BUILD_PAIR_UNSIGNED("Flags", link->flags),
1180                                 JSON_BUILD_PAIR_STRING("FlagsString", flags),
1181                                 JSON_BUILD_PAIR_UNSIGNED("KernelOperationalState", link->kernel_operstate),
1182                                 JSON_BUILD_PAIR_STRING("KernelOperationalStateString", kernel_operstate_to_string(link->kernel_operstate)),
1183                                 JSON_BUILD_PAIR_UNSIGNED("MTU", link->mtu),
1184                                 JSON_BUILD_PAIR_UNSIGNED("MinimumMTU", link->min_mtu),
1185                                 JSON_BUILD_PAIR_UNSIGNED("MaximumMTU", link->max_mtu),
1186                                 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("HardwareAddress", &link->hw_addr),
1187                                 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("PermanentHardwareAddress", &link->permanent_hw_addr),
1188                                 JSON_BUILD_PAIR_HW_ADDR_NON_NULL("BroadcastAddress", &link->bcast_addr),
1189                                 JSON_BUILD_PAIR_IN6_ADDR_NON_NULL("IPv6LinkLocalAddress", &link->ipv6ll_address),
1190                                 /* wlan information */
1191                                 JSON_BUILD_PAIR_CONDITION(link->wlan_iftype > 0, "WirelessLanInterfaceType",
1192                                                           JSON_BUILD_UNSIGNED(link->wlan_iftype)),
1193                                 JSON_BUILD_PAIR_CONDITION(link->wlan_iftype > 0, "WirelessLanInterfaceTypeString",
1194                                                           JSON_BUILD_STRING(nl80211_iftype_to_string(link->wlan_iftype))),
1195                                 JSON_BUILD_PAIR_STRING_NON_EMPTY("SSID", link->ssid),
1196                                 JSON_BUILD_PAIR_ETHER_ADDR_NON_NULL("BSSID", &link->bssid),
1197                                 /* link state */
1198                                 JSON_BUILD_PAIR_STRING("AdministrativeState", link_state_to_string(link->state)),
1199                                 JSON_BUILD_PAIR_STRING("OperationalState", link_operstate_to_string(link->operstate)),
1200                                 JSON_BUILD_PAIR_STRING("CarrierState", link_carrier_state_to_string(link->carrier_state)),
1201                                 JSON_BUILD_PAIR_STRING("AddressState", link_address_state_to_string(link->address_state)),
1202                                 JSON_BUILD_PAIR_STRING("IPv4AddressState", link_address_state_to_string(link->ipv4_address_state)),
1203                                 JSON_BUILD_PAIR_STRING("IPv6AddressState", link_address_state_to_string(link->ipv6_address_state)),
1204                                 JSON_BUILD_PAIR_STRING("OnlineState", link_online_state_to_string(link->online_state))));
1205         if (r < 0)
1206                 return r;
1207 
1208         r = network_build_json(link->network, &w);
1209         if (r < 0)
1210                 return r;
1211 
1212         r = json_variant_merge(&v, w);
1213         if (r < 0)
1214                 return r;
1215 
1216         w = json_variant_unref(w);
1217 
1218         r = device_build_json(link->sd_device, &w);
1219         if (r < 0)
1220                 return r;
1221 
1222         r = json_variant_merge(&v, w);
1223         if (r < 0)
1224                 return r;
1225 
1226         w = json_variant_unref(w);
1227 
1228         r = dns_build_json(link, &w);
1229         if (r < 0)
1230                 return r;
1231 
1232         r = json_variant_merge(&v, w);
1233         if (r < 0)
1234                 return r;
1235 
1236         w = json_variant_unref(w);
1237 
1238         r = ntp_build_json(link, &w);
1239         if (r < 0)
1240                 return r;
1241 
1242         r = json_variant_merge(&v, w);
1243         if (r < 0)
1244                 return r;
1245 
1246         w = json_variant_unref(w);
1247 
1248         r = sip_build_json(link, &w);
1249         if (r < 0)
1250                 return r;
1251 
1252         r = json_variant_merge(&v, w);
1253         if (r < 0)
1254                 return r;
1255 
1256         w = json_variant_unref(w);
1257 
1258         r = domains_build_json(link, /* is_route = */ false, &w);
1259         if (r < 0)
1260                 return r;
1261 
1262         r = json_variant_merge(&v, w);
1263         if (r < 0)
1264                 return r;
1265 
1266         w = json_variant_unref(w);
1267 
1268         r = domains_build_json(link, /* is_route = */ true, &w);
1269         if (r < 0)
1270                 return r;
1271 
1272         r = json_variant_merge(&v, w);
1273         if (r < 0)
1274                 return r;
1275 
1276         w = json_variant_unref(w);
1277 
1278         r = ntas_build_json(link, &w);
1279         if (r < 0)
1280                 return r;
1281 
1282         r = json_variant_merge(&v, w);
1283         if (r < 0)
1284                 return r;
1285 
1286         w = json_variant_unref(w);
1287 
1288         r = dns_misc_build_json(link, &w);
1289         if (r < 0)
1290                 return r;
1291 
1292         r = json_variant_merge(&v, w);
1293         if (r < 0)
1294                 return r;
1295 
1296         w = json_variant_unref(w);
1297 
1298         r = addresses_build_json(link->addresses, &w);
1299         if (r < 0)
1300                 return r;
1301 
1302         r = json_variant_merge(&v, w);
1303         if (r < 0)
1304                 return r;
1305 
1306         w = json_variant_unref(w);
1307 
1308         r = neighbors_build_json(link->neighbors, &w);
1309         if (r < 0)
1310                 return r;
1311 
1312         r = json_variant_merge(&v, w);
1313         if (r < 0)
1314                 return r;
1315 
1316         w = json_variant_unref(w);
1317 
1318         r = nexthops_build_json(link->nexthops, &w);
1319         if (r < 0)
1320                 return r;
1321 
1322         r = json_variant_merge(&v, w);
1323         if (r < 0)
1324                 return r;
1325 
1326         w = json_variant_unref(w);
1327 
1328         r = routes_build_json(link->routes, &w);
1329         if (r < 0)
1330                 return r;
1331 
1332         r = json_variant_merge(&v, w);
1333         if (r < 0)
1334                 return r;
1335 
1336         *ret = TAKE_PTR(v);
1337         return 0;
1338 }
1339 
link_json_compare(JsonVariant * const * a,JsonVariant * const * b)1340 static int link_json_compare(JsonVariant * const *a, JsonVariant * const *b) {
1341         int64_t index_a, index_b;
1342 
1343         assert(a && *a);
1344         assert(b && *b);
1345 
1346         index_a = json_variant_integer(json_variant_by_key(*a, "Index"));
1347         index_b = json_variant_integer(json_variant_by_key(*b, "Index"));
1348 
1349         return CMP(index_a, index_b);
1350 }
1351 
links_build_json(Manager * manager,JsonVariant ** ret)1352 static int links_build_json(Manager *manager, JsonVariant **ret) {
1353         JsonVariant **elements;
1354         Link *link;
1355         size_t n = 0;
1356         int r;
1357 
1358         assert(manager);
1359         assert(ret);
1360 
1361         elements = new(JsonVariant*, hashmap_size(manager->links_by_index));
1362         if (!elements)
1363                 return -ENOMEM;
1364 
1365         HASHMAP_FOREACH(link, manager->links_by_index) {
1366                 r = link_build_json(link, elements + n);
1367                 if (r < 0)
1368                         goto finalize;
1369                 n++;
1370         }
1371 
1372         typesafe_qsort(elements, n, link_json_compare);
1373 
1374         r = json_build(ret, JSON_BUILD_OBJECT(JSON_BUILD_PAIR("Interfaces", JSON_BUILD_VARIANT_ARRAY(elements, n))));
1375 
1376 finalize:
1377         json_variant_unref_many(elements, n);
1378         free(elements);
1379         return r;
1380 }
1381 
manager_build_json(Manager * manager,JsonVariant ** ret)1382 int manager_build_json(Manager *manager, JsonVariant **ret) {
1383         _cleanup_(json_variant_unrefp) JsonVariant *v = NULL, *w = NULL;
1384         int r;
1385 
1386         assert(manager);
1387         assert(ret);
1388 
1389         r = links_build_json(manager, &v);
1390         if (r < 0)
1391                 return r;
1392 
1393         r = nexthops_build_json(manager->nexthops, &w);
1394         if (r < 0)
1395                 return r;
1396 
1397         r = json_variant_merge(&v, w);
1398         if (r < 0)
1399                 return r;
1400 
1401         w = json_variant_unref(w);
1402 
1403         r = routes_build_json(manager->routes, &w);
1404         if (r < 0)
1405                 return r;
1406 
1407         r = json_variant_merge(&v, w);
1408         if (r < 0)
1409                 return r;
1410 
1411         w = json_variant_unref(w);
1412 
1413         r = routing_policy_rules_build_json(manager->rules, &w);
1414         if (r < 0)
1415                 return r;
1416 
1417         r = json_variant_merge(&v, w);
1418         if (r < 0)
1419                 return r;
1420 
1421         *ret = TAKE_PTR(v);
1422         return 0;
1423 }
1424