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