1*81a06611Sclaudio /*	$OpenBSD: output-json.c,v 1.49 2024/04/21 19:27:44 claudio Exp $ */
2a382efa2Sclaudio /*
3a382efa2Sclaudio  * Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
4a382efa2Sclaudio  *
5a382efa2Sclaudio  * Permission to use, copy, modify, and distribute this software for any
6a382efa2Sclaudio  * purpose with or without fee is hereby granted, provided that the above
7a382efa2Sclaudio  * copyright notice and this permission notice appear in all copies.
8a382efa2Sclaudio  *
9a382efa2Sclaudio  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10a382efa2Sclaudio  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11a382efa2Sclaudio  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12a382efa2Sclaudio  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13a382efa2Sclaudio  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14a382efa2Sclaudio  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15a382efa2Sclaudio  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16a382efa2Sclaudio  */
17a382efa2Sclaudio 
18a382efa2Sclaudio #include <stdlib.h>
190ee5ab88Sderaadt #include <unistd.h>
209962cf41Sderaadt #include <time.h>
210ee5ab88Sderaadt #include <netdb.h>
22a382efa2Sclaudio 
23a382efa2Sclaudio #include "extern.h"
2415797777Sclaudio #include "json.h"
25a382efa2Sclaudio 
2615797777Sclaudio static void
outputheader_json(struct stats * st)2715797777Sclaudio outputheader_json(struct stats *st)
280ee5ab88Sderaadt {
290ee5ab88Sderaadt 	char		 hn[NI_MAXHOST], tbuf[26];
309962cf41Sderaadt 	struct tm	*tp;
310ee5ab88Sderaadt 	time_t		 t;
32389eb209Sclaudio 	int		 i;
330ee5ab88Sderaadt 
340ee5ab88Sderaadt 	time(&t);
3565c2098bStb 	tp = gmtime(&t);
369962cf41Sderaadt 	strftime(tbuf, sizeof tbuf, "%FT%TZ", tp);
370ee5ab88Sderaadt 
380ee5ab88Sderaadt 	gethostname(hn, sizeof hn);
390ee5ab88Sderaadt 
40a09a3191Sclaudio 	json_do_object("metadata", 0);
41dc508150Sclaudio 
42b1f57218Sclaudio 	json_do_string("buildmachine", hn);
43b1f57218Sclaudio 	json_do_string("buildtime", tbuf);
4415797777Sclaudio 	json_do_int("elapsedtime", st->elapsed_time.tv_sec);
4515797777Sclaudio 	json_do_int("usertime", st->user_time.tv_sec);
4615797777Sclaudio 	json_do_int("systemtime", st->system_time.tv_sec);
4715797777Sclaudio 	json_do_int("roas", st->repo_tal_stats.roas);
4815797777Sclaudio 	json_do_int("failedroas", st->repo_tal_stats.roas_fail);
4915797777Sclaudio 	json_do_int("invalidroas", st->repo_tal_stats.roas_invalid);
50d4be4cdeSjob 	json_do_int("spls", st->repo_tal_stats.spls);
51d4be4cdeSjob 	json_do_int("failedspls", st->repo_tal_stats.spls_fail);
52d4be4cdeSjob 	json_do_int("invalidspls", st->repo_tal_stats.spls_invalid);
5315797777Sclaudio 	json_do_int("aspas", st->repo_tal_stats.aspas);
5415797777Sclaudio 	json_do_int("failedaspas", st->repo_tal_stats.aspas_fail);
5515797777Sclaudio 	json_do_int("invalidaspas", st->repo_tal_stats.aspas_invalid);
5615797777Sclaudio 	json_do_int("bgpsec_pubkeys", st->repo_tal_stats.brks);
5715797777Sclaudio 	json_do_int("certificates", st->repo_tal_stats.certs);
5815797777Sclaudio 	json_do_int("invalidcertificates", st->repo_tal_stats.certs_fail);
5915797777Sclaudio 	json_do_int("taks", st->repo_tal_stats.taks);
6015797777Sclaudio 	json_do_int("tals", st->tals);
6115797777Sclaudio 	json_do_int("invalidtals", talsz - st->tals);
6215797777Sclaudio 
6315797777Sclaudio 	json_do_array("talfiles");
6415797777Sclaudio 	for (i = 0; i < talsz; i++)
65b1f57218Sclaudio 		json_do_string("name", tals[i]);
6615797777Sclaudio 	json_do_end();
6715797777Sclaudio 
6815797777Sclaudio 	json_do_int("manifests", st->repo_tal_stats.mfts);
6915797777Sclaudio 	json_do_int("failedmanifests", st->repo_tal_stats.mfts_fail);
7015797777Sclaudio 	json_do_int("crls", st->repo_tal_stats.crls);
7115797777Sclaudio 	json_do_int("gbrs", st->repo_tal_stats.gbrs);
7215797777Sclaudio 	json_do_int("repositories", st->repos);
7315797777Sclaudio 	json_do_int("vrps", st->repo_tal_stats.vrps);
7415797777Sclaudio 	json_do_int("uniquevrps", st->repo_tal_stats.vrps_uniqs);
75d4be4cdeSjob 	json_do_int("vsps", st->repo_tal_stats.vsps);
76d4be4cdeSjob 	json_do_int("uniquevsps", st->repo_tal_stats.vsps_uniqs);
7715797777Sclaudio 	json_do_int("vaps", st->repo_tal_stats.vaps);
7815797777Sclaudio 	json_do_int("uniquevaps", st->repo_tal_stats.vaps_uniqs);
79a5f50487Sjob 	json_do_int("cachedir_new_files", st->repo_stats.new_files);
8015797777Sclaudio 	json_do_int("cachedir_del_files", st->repo_stats.del_files);
8115797777Sclaudio 	json_do_int("cachedir_del_dirs", st->repo_stats.del_dirs);
821438586aSclaudio 	json_do_int("cachedir_superfluous_files", st->repo_stats.extra_files);
831438586aSclaudio 	json_do_int("cachedir_del_superfluous_files",
841438586aSclaudio 	    st->repo_stats.del_extra_files);
8515797777Sclaudio 
8615797777Sclaudio 	json_do_end();
87dc508150Sclaudio }
88dc508150Sclaudio 
8915797777Sclaudio static void
print_vap(struct vap * v)904b5fc138Sjob print_vap(struct vap *v)
91a29ddfd5Sjob {
9215797777Sclaudio 	size_t i;
93a29ddfd5Sjob 
947e284d50Stb 	if (v->overflowed)
95cd55b6bdSjob 		return;
96cd55b6bdSjob 
97a09a3191Sclaudio 	json_do_object("aspa", 1);
9815797777Sclaudio 	json_do_int("customer_asid", v->custasid);
9915797777Sclaudio 	json_do_int("expires", v->expires);
10038f92035Sjob 
10115797777Sclaudio 	json_do_array("providers");
1024b5fc138Sjob 	for (i = 0; i < v->providersz; i++)
1034b5fc138Sjob 		json_do_int("provider", v->providers[i]);
1044b5fc138Sjob 
10515797777Sclaudio 	json_do_end();
106a29ddfd5Sjob }
10714b6717bSjob 
10815797777Sclaudio static void
output_aspa(struct vap_tree * vaps)10915797777Sclaudio output_aspa(struct vap_tree *vaps)
110a29ddfd5Sjob {
111a29ddfd5Sjob 	struct vap	*v;
112a29ddfd5Sjob 
1134b5fc138Sjob 	json_do_array("aspas");
1144b5fc138Sjob 	RB_FOREACH(v, vap_tree, vaps)
1154b5fc138Sjob 		print_vap(v);
11615797777Sclaudio 	json_do_end();
117a29ddfd5Sjob }
118a29ddfd5Sjob 
119ad406917Stb static void
output_spl(struct vsp_tree * vsps)120ad406917Stb output_spl(struct vsp_tree *vsps)
121ad406917Stb {
122ad406917Stb 	struct vsp	*vsp;
123ad406917Stb 	char		 buf[64];
124ad406917Stb 	size_t		 i;
125ad406917Stb 
126ad406917Stb 	json_do_array("signedprefixlists");
127ad406917Stb 	RB_FOREACH(vsp, vsp_tree, vsps) {
128ad406917Stb 		json_do_object("vsp", 1);
129ad406917Stb 		json_do_int("origin_as", vsp->asid);
130ad406917Stb 		json_do_array("prefixes");
131ad406917Stb 		for (i = 0; i < vsp->prefixesz; i++) {
132ad406917Stb 			ip_addr_print(&vsp->prefixes[i].prefix,
133ad406917Stb 			    vsp->prefixes[i].afi, buf, sizeof(buf));
134ad406917Stb 			json_do_string("prefix", buf);
135ad406917Stb 		}
136ad406917Stb 		json_do_end();
137ad406917Stb 		json_do_int("expires", vsp->expires);
138ad406917Stb 		json_do_string("ta", taldescs[vsp->talid]);
139ad406917Stb 		json_do_end();
140ad406917Stb 	}
141ad406917Stb 	json_do_end();
142ad406917Stb }
143ad406917Stb 
1441f9a8b94Sderaadt int
output_json(FILE * out,struct vrp_tree * vrps,struct brk_tree * brks,struct vap_tree * vaps,struct vsp_tree * vsps,struct stats * st)1456b83d8e3Sjob output_json(FILE *out, struct vrp_tree *vrps, struct brk_tree *brks,
146d4be4cdeSjob     struct vap_tree *vaps, struct vsp_tree *vsps, struct stats *st)
147a382efa2Sclaudio {
148a382efa2Sclaudio 	char		 buf[64];
149a382efa2Sclaudio 	struct vrp	*v;
1506b83d8e3Sjob 	struct brk	*b;
151ed26e04bSderaadt 
15215797777Sclaudio 	json_do_start(out);
15315797777Sclaudio 	outputheader_json(st);
1540ee5ab88Sderaadt 
15515797777Sclaudio 	json_do_array("roas");
156a382efa2Sclaudio 	RB_FOREACH(v, vrp_tree, vrps) {
157a382efa2Sclaudio 		ip_addr_print(&v->addr, v->afi, buf, sizeof(buf));
158a382efa2Sclaudio 
159a09a3191Sclaudio 		json_do_object("roa", 1);
16015797777Sclaudio 		json_do_int("asn", v->asid);
161b1f57218Sclaudio 		json_do_string("prefix", buf);
16215797777Sclaudio 		json_do_int("maxLength", v->maxlength);
163b1f57218Sclaudio 		json_do_string("ta", taldescs[v->talid]);
16415797777Sclaudio 		json_do_int("expires", v->expires);
16515797777Sclaudio 		json_do_end();
166a382efa2Sclaudio 	}
16715797777Sclaudio 	json_do_end();
168a382efa2Sclaudio 
16915797777Sclaudio 	json_do_array("bgpsec_keys");
1706b83d8e3Sjob 	RB_FOREACH(b, brk_tree, brks) {
171a09a3191Sclaudio 		json_do_object("brks", 0);
17215797777Sclaudio 		json_do_int("asn", b->asid);
173b1f57218Sclaudio 		json_do_string("ski", b->ski);
174b1f57218Sclaudio 		json_do_string("pubkey", b->pubkey);
175b1f57218Sclaudio 		json_do_string("ta", taldescs[b->talid]);
17615797777Sclaudio 		json_do_int("expires", b->expires);
17715797777Sclaudio 		json_do_end();
1786b83d8e3Sjob 	}
17915797777Sclaudio 	json_do_end();
1806b83d8e3Sjob 
18115797777Sclaudio 	if (!excludeaspa)
18215797777Sclaudio 		output_aspa(vaps);
1836b83d8e3Sjob 
1849463abd5Stb 	if (experimental)
185ad406917Stb 		output_spl(vsps);
186d4be4cdeSjob 
18715797777Sclaudio 	return json_do_finish();
188a382efa2Sclaudio }
189