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