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 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 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 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 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 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