1 /* $OpenBSD: output-json.c,v 1.51 2024/11/13 12:51:04 tb Exp $ */
2 /*
3 * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
6 * purpose with or without fee is hereby granted, provided that the above
7 * copyright notice and this permission notice appear in all copies.
8 *
9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18 #include <stdlib.h>
19 #include <unistd.h>
20 #include <time.h>
21 #include <netdb.h>
22
23 #include "extern.h"
24 #include "json.h"
25
26 static void
outputheader_json(struct stats * st)27 outputheader_json(struct stats *st)
28 {
29 char hn[NI_MAXHOST], tbuf[26];
30 struct tm *tp;
31 time_t t;
32 int i;
33
34 time(&t);
35 tp = gmtime(&t);
36 strftime(tbuf, sizeof tbuf, "%FT%TZ", tp);
37
38 gethostname(hn, sizeof hn);
39
40 json_do_object("metadata", 0);
41
42 json_do_string("buildmachine", hn);
43 json_do_string("buildtime", tbuf);
44 json_do_int("elapsedtime", st->elapsed_time.tv_sec);
45 json_do_int("usertime", st->user_time.tv_sec);
46 json_do_int("systemtime", st->system_time.tv_sec);
47 json_do_int("roas", st->repo_tal_stats.roas);
48 json_do_int("failedroas", st->repo_tal_stats.roas_fail);
49 json_do_int("invalidroas", st->repo_tal_stats.roas_invalid);
50 if (experimental) {
51 json_do_int("spls", st->repo_tal_stats.spls);
52 json_do_int("failedspls", st->repo_tal_stats.spls_fail);
53 json_do_int("invalidspls", st->repo_tal_stats.spls_invalid);
54 }
55 json_do_int("aspas", st->repo_tal_stats.aspas);
56 json_do_int("failedaspas", st->repo_tal_stats.aspas_fail);
57 json_do_int("invalidaspas", st->repo_tal_stats.aspas_invalid);
58 json_do_int("bgpsec_pubkeys", st->repo_tal_stats.brks);
59 json_do_int("certificates", st->repo_tal_stats.certs);
60 json_do_int("invalidcertificates", st->repo_tal_stats.certs_fail);
61 json_do_int("taks", st->repo_tal_stats.taks);
62 json_do_int("tals", st->tals);
63 json_do_int("invalidtals", talsz - st->tals);
64
65 json_do_array("talfiles");
66 for (i = 0; i < talsz; i++)
67 json_do_string("name", tals[i]);
68 json_do_end();
69
70 json_do_int("manifests", st->repo_tal_stats.mfts);
71 json_do_int("failedmanifests", st->repo_tal_stats.mfts_fail);
72 json_do_int("crls", st->repo_tal_stats.crls);
73 json_do_int("gbrs", st->repo_tal_stats.gbrs);
74 json_do_int("repositories", st->repos);
75 json_do_int("vrps", st->repo_tal_stats.vrps);
76 json_do_int("uniquevrps", st->repo_tal_stats.vrps_uniqs);
77 json_do_int("vsps", st->repo_tal_stats.vsps);
78 json_do_int("uniquevsps", st->repo_tal_stats.vsps_uniqs);
79 json_do_int("vaps", st->repo_tal_stats.vaps);
80 json_do_int("uniquevaps", st->repo_tal_stats.vaps_uniqs);
81 json_do_int("cachedir_new_files", st->repo_stats.new_files);
82 json_do_int("cachedir_del_files", st->repo_stats.del_files);
83 json_do_int("cachedir_del_dirs", st->repo_stats.del_dirs);
84 json_do_int("cachedir_superfluous_files", st->repo_stats.extra_files);
85 json_do_int("cachedir_del_superfluous_files",
86 st->repo_stats.del_extra_files);
87
88 json_do_end();
89 }
90
91 static void
print_vap(struct vap * v)92 print_vap(struct vap *v)
93 {
94 size_t i;
95
96 if (v->overflowed)
97 return;
98
99 json_do_object("aspa", 1);
100 json_do_int("customer_asid", v->custasid);
101 json_do_int("expires", v->expires);
102
103 json_do_array("providers");
104 for (i = 0; i < v->num_providers; i++)
105 json_do_int("provider", v->providers[i]);
106
107 json_do_end();
108 }
109
110 static void
output_aspa(struct vap_tree * vaps)111 output_aspa(struct vap_tree *vaps)
112 {
113 struct vap *v;
114
115 json_do_array("aspas");
116 RB_FOREACH(v, vap_tree, vaps)
117 print_vap(v);
118 json_do_end();
119 }
120
121 static void
output_spl(struct vsp_tree * vsps)122 output_spl(struct vsp_tree *vsps)
123 {
124 struct vsp *vsp;
125 char buf[64];
126 size_t i;
127
128 json_do_array("signedprefixlists");
129 RB_FOREACH(vsp, vsp_tree, vsps) {
130 json_do_object("vsp", 1);
131 json_do_int("origin_as", vsp->asid);
132 json_do_array("prefixes");
133 for (i = 0; i < vsp->num_prefixes; i++) {
134 ip_addr_print(&vsp->prefixes[i].prefix,
135 vsp->prefixes[i].afi, buf, sizeof(buf));
136 json_do_string("prefix", buf);
137 }
138 json_do_end();
139 json_do_int("expires", vsp->expires);
140 json_do_string("ta", taldescs[vsp->talid]);
141 json_do_end();
142 }
143 json_do_end();
144 }
145
146 int
output_json(FILE * out,struct vrp_tree * vrps,struct brk_tree * brks,struct vap_tree * vaps,struct vsp_tree * vsps,struct stats * st)147 output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
148 struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st)
149 {
150 char buf[64];
151 struct vrp *v;
152 struct brk *b;
153
154 json_do_start(out);
155 outputheader_json(st);
156
157 json_do_array("roas");
158 RB_FOREACH(v, vrp_tree, vrps) {
159 ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
160
161 json_do_object("roa", 1);
162 json_do_int("asn", v->asid);
163 json_do_string("prefix", buf);
164 json_do_int("maxLength", v->maxlength);
165 json_do_string("ta", taldescs[v->talid]);
166 json_do_int("expires", v->expires);
167 json_do_end();
168 }
169 json_do_end();
170
171 json_do_array("bgpsec_keys");
172 RB_FOREACH(b, brk_tree, brks) {
173 json_do_object("brks", 0);
174 json_do_int("asn", b->asid);
175 json_do_string("ski", b->ski);
176 json_do_string("pubkey", b->pubkey);
177 json_do_string("ta", taldescs[b->talid]);
178 json_do_int("expires", b->expires);
179 json_do_end();
180 }
181 json_do_end();
182
183 if (!excludeaspa)
184 output_aspa(vaps);
185
186 if (experimental)
187 output_spl(vsps);
188
189 return json_do_finish();
190 }
191