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