1 /* $OpenBSD: main.c,v 1.260 2024/06/08 13:31:38 tb Exp $ */
2 /*
3 * Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
4 * Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
5 *
6 * Permission to use, copy, modify, and distribute this software for any
7 * purpose with or without fee is hereby granted, provided that the above
8 * copyright notice and this permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
17 */
18
19 #include <sys/types.h>
20 #include <sys/queue.h>
21 #include <sys/resource.h>
22 #include <sys/socket.h>
23 #include <sys/statvfs.h>
24 #include <sys/time.h>
25 #include <sys/tree.h>
26 #include <sys/wait.h>
27
28 #include <assert.h>
29 #include <dirent.h>
30 #include <err.h>
31 #include <errno.h>
32 #include <fcntl.h>
33 #include <fnmatch.h>
34 #include <limits.h>
35 #include <poll.h>
36 #include <pwd.h>
37 #include <signal.h>
38 #include <stdarg.h>
39 #include <stdio.h>
40 #include <stdlib.h>
41 #include <string.h>
42 #include <syslog.h>
43 #include <time.h>
44 #include <unistd.h>
45
46 #include <imsg.h>
47
48 #include "extern.h"
49 #include "version.h"
50
51 const char *tals[TALSZ_MAX];
52 const char *taldescs[TALSZ_MAX];
53 unsigned int talrepocnt[TALSZ_MAX];
54 struct repotalstats talstats[TALSZ_MAX];
55 int talsz;
56
57 size_t entity_queue;
58 int timeout = 60*60;
59 volatile sig_atomic_t killme;
60 void suicide(int sig);
61
62 static struct filepath_tree fpt = RB_INITIALIZER(&fpt);
63 static struct msgbuf procq, rsyncq, httpq, rrdpq;
64 static int cachefd, outdirfd;
65
66 const char *bird_tablename = "ROAS";
67
68 int verbose;
69 int noop;
70 int excludeaspa;
71 int filemode;
72 int shortlistmode;
73 int rrdpon = 1;
74 int repo_timeout;
75 int experimental;
76 time_t deadline;
77
78 /* 9999-12-31 23:59:59 UTC */
79 #define X509_TIME_MAX 253402300799LL
80 /* 0000-01-01 00:00:00 UTC */
81 #define X509_TIME_MIN -62167219200LL
82
83 int64_t evaluation_time = X509_TIME_MIN;
84
85 struct stats stats;
86
87 struct fqdnlistentry {
88 LIST_ENTRY(fqdnlistentry) entry;
89 char *fqdn;
90 };
91 LIST_HEAD(fqdns, fqdnlistentry);
92
93 struct fqdns shortlist = LIST_HEAD_INITIALIZER(fqdns);
94 struct fqdns skiplist = LIST_HEAD_INITIALIZER(fqdns);
95
96 /*
97 * Log a message to stderr if and only if "verbose" is non-zero.
98 * This uses the err(3) functionality.
99 */
100 void
logx(const char * fmt,...)101 logx(const char *fmt, ...)
102 {
103 va_list ap;
104
105 if (verbose && fmt != NULL) {
106 va_start(ap, fmt);
107 vwarnx(fmt, ap);
108 va_end(ap);
109 }
110 }
111
112 time_t
getmonotime(void)113 getmonotime(void)
114 {
115 struct timespec ts;
116
117 if (clock_gettime(CLOCK_MONOTONIC, &ts) != 0)
118 err(1, "clock_gettime");
119 return (ts.tv_sec);
120 }
121
122 /*
123 * Time - Evaluation time is used as the current time if it is
124 * larger than X509_TIME_MIN, otherwise the system time is used.
125 */
126 time_t
get_current_time(void)127 get_current_time(void)
128 {
129 if (evaluation_time > X509_TIME_MIN)
130 return (time_t)evaluation_time;
131 return time(NULL);
132 }
133
134 void
entity_free(struct entity * ent)135 entity_free(struct entity *ent)
136 {
137 if (ent == NULL)
138 return;
139
140 free(ent->path);
141 free(ent->file);
142 free(ent->mftaki);
143 free(ent->data);
144 free(ent);
145 }
146
147 /*
148 * Read a queue entity from the descriptor.
149 * Matched by entity_write_req().
150 * The pointer must be passed entity_free().
151 */
152 void
entity_read_req(struct ibuf * b,struct entity * ent)153 entity_read_req(struct ibuf *b, struct entity *ent)
154 {
155 io_read_buf(b, &ent->type, sizeof(ent->type));
156 io_read_buf(b, &ent->location, sizeof(ent->location));
157 io_read_buf(b, &ent->repoid, sizeof(ent->repoid));
158 io_read_buf(b, &ent->talid, sizeof(ent->talid));
159 io_read_buf(b, &ent->certid, sizeof(ent->certid));
160 io_read_str(b, &ent->path);
161 io_read_str(b, &ent->file);
162 io_read_str(b, &ent->mftaki);
163 io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz);
164 }
165
166 /*
167 * Write the queue entity.
168 * Matched by entity_read_req().
169 */
170 static void
entity_write_req(const struct entity * ent)171 entity_write_req(const struct entity *ent)
172 {
173 struct ibuf *b;
174
175 b = io_new_buffer();
176 io_simple_buffer(b, &ent->type, sizeof(ent->type));
177 io_simple_buffer(b, &ent->location, sizeof(ent->location));
178 io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid));
179 io_simple_buffer(b, &ent->talid, sizeof(ent->talid));
180 io_simple_buffer(b, &ent->certid, sizeof(ent->certid));
181 io_str_buffer(b, ent->path);
182 io_str_buffer(b, ent->file);
183 io_str_buffer(b, ent->mftaki);
184 io_buf_buffer(b, ent->data, ent->datasz);
185 io_close_buffer(&procq, b);
186 }
187
188 static void
entity_write_repo(const struct repo * rp)189 entity_write_repo(const struct repo *rp)
190 {
191 struct ibuf *b;
192 enum rtype type = RTYPE_REPO;
193 enum location loc = DIR_UNKNOWN;
194 unsigned int repoid;
195 char *path, *altpath;
196 int talid = 0, certid = 0;
197
198 repoid = repo_id(rp);
199 path = repo_basedir(rp, 0);
200 altpath = repo_basedir(rp, 1);
201 b = io_new_buffer();
202 io_simple_buffer(b, &type, sizeof(type));
203 io_simple_buffer(b, &loc, sizeof(loc));
204 io_simple_buffer(b, &repoid, sizeof(repoid));
205 io_simple_buffer(b, &talid, sizeof(talid));
206 io_simple_buffer(b, &certid, sizeof(certid));
207 io_str_buffer(b, path);
208 io_str_buffer(b, altpath);
209 io_buf_buffer(b, NULL, 0); /* ent->mftaki */
210 io_buf_buffer(b, NULL, 0); /* ent->data */
211 io_close_buffer(&procq, b);
212 free(path);
213 free(altpath);
214 }
215
216 /*
217 * Scan through all queued requests and see which ones are in the given
218 * repo, then flush those into the parser process.
219 */
220 void
entityq_flush(struct entityq * q,struct repo * rp)221 entityq_flush(struct entityq *q, struct repo *rp)
222 {
223 struct entity *p, *np;
224
225 entity_write_repo(rp);
226
227 TAILQ_FOREACH_SAFE(p, q, entries, np) {
228 entity_write_req(p);
229 TAILQ_REMOVE(q, p, entries);
230 entity_free(p);
231 }
232 }
233
234 /*
235 * Add the heap-allocated file to the queue for processing.
236 */
237 static void
entityq_add(char * path,char * file,enum rtype type,enum location loc,struct repo * rp,unsigned char * data,size_t datasz,int talid,int certid,char * mftaki)238 entityq_add(char *path, char *file, enum rtype type, enum location loc,
239 struct repo *rp, unsigned char *data, size_t datasz, int talid, int certid,
240 char *mftaki)
241 {
242 struct entity *p;
243
244 if ((p = calloc(1, sizeof(struct entity))) == NULL)
245 err(1, NULL);
246
247 p->type = type;
248 p->location = loc;
249 p->talid = talid;
250 p->certid = certid;
251 p->mftaki = mftaki;
252 p->path = path;
253 if (rp != NULL)
254 p->repoid = repo_id(rp);
255 p->file = file;
256 p->data = data;
257 p->datasz = (data != NULL) ? datasz : 0;
258
259 entity_queue++;
260
261 /*
262 * Write to the queue if there's no repo or the repo has already
263 * been loaded else enqueue it for later.
264 */
265
266 if (rp == NULL || !repo_queued(rp, p)) {
267 entity_write_req(p);
268 entity_free(p);
269 }
270 }
271
272 static void
rrdp_file_resp(unsigned int id,int ok)273 rrdp_file_resp(unsigned int id, int ok)
274 {
275 enum rrdp_msg type = RRDP_FILE;
276 struct ibuf *b;
277
278 b = io_new_buffer();
279 io_simple_buffer(b, &type, sizeof(type));
280 io_simple_buffer(b, &id, sizeof(id));
281 io_simple_buffer(b, &ok, sizeof(ok));
282 io_close_buffer(&rrdpq, b);
283 }
284
285 void
rrdp_fetch(unsigned int id,const char * uri,const char * local,struct rrdp_session * s)286 rrdp_fetch(unsigned int id, const char *uri, const char *local,
287 struct rrdp_session *s)
288 {
289 enum rrdp_msg type = RRDP_START;
290 struct ibuf *b;
291
292 b = io_new_buffer();
293 io_simple_buffer(b, &type, sizeof(type));
294 io_simple_buffer(b, &id, sizeof(id));
295 io_str_buffer(b, local);
296 io_str_buffer(b, uri);
297
298 rrdp_session_buffer(b, s);
299 io_close_buffer(&rrdpq, b);
300 }
301
302 void
rrdp_abort(unsigned int id)303 rrdp_abort(unsigned int id)
304 {
305 enum rrdp_msg type = RRDP_ABORT;
306 struct ibuf *b;
307
308 b = io_new_buffer();
309 io_simple_buffer(b, &type, sizeof(type));
310 io_simple_buffer(b, &id, sizeof(id));
311 io_close_buffer(&rrdpq, b);
312 }
313
314 /*
315 * Request a repository sync via rsync URI to directory local.
316 */
317 void
rsync_fetch(unsigned int id,const char * uri,const char * local,const char * base)318 rsync_fetch(unsigned int id, const char *uri, const char *local,
319 const char *base)
320 {
321 struct ibuf *b;
322
323 b = io_new_buffer();
324 io_simple_buffer(b, &id, sizeof(id));
325 io_str_buffer(b, local);
326 io_str_buffer(b, base);
327 io_str_buffer(b, uri);
328 io_close_buffer(&rsyncq, b);
329 }
330
331 void
rsync_abort(unsigned int id)332 rsync_abort(unsigned int id)
333 {
334 struct ibuf *b;
335
336 b = io_new_buffer();
337 io_simple_buffer(b, &id, sizeof(id));
338 io_str_buffer(b, NULL);
339 io_str_buffer(b, NULL);
340 io_str_buffer(b, NULL);
341 io_close_buffer(&rsyncq, b);
342 }
343
344 /*
345 * Request a file from a https uri, data is written to the file descriptor fd.
346 */
347 void
http_fetch(unsigned int id,const char * uri,const char * last_mod,int fd)348 http_fetch(unsigned int id, const char *uri, const char *last_mod, int fd)
349 {
350 struct ibuf *b;
351
352 b = io_new_buffer();
353 io_simple_buffer(b, &id, sizeof(id));
354 io_str_buffer(b, uri);
355 io_str_buffer(b, last_mod);
356 /* pass file as fd */
357 ibuf_fd_set(b, fd);
358 io_close_buffer(&httpq, b);
359 }
360
361 /*
362 * Request some XML file on behalf of the rrdp parser.
363 * Create a pipe and pass the pipe endpoints to the http and rrdp process.
364 */
365 static void
rrdp_http_fetch(unsigned int id,const char * uri,const char * last_mod)366 rrdp_http_fetch(unsigned int id, const char *uri, const char *last_mod)
367 {
368 enum rrdp_msg type = RRDP_HTTP_INI;
369 struct ibuf *b;
370 int pi[2];
371
372 if (pipe2(pi, O_CLOEXEC | O_NONBLOCK) == -1)
373 err(1, "pipe");
374
375 b = io_new_buffer();
376 io_simple_buffer(b, &type, sizeof(type));
377 io_simple_buffer(b, &id, sizeof(id));
378 ibuf_fd_set(b, pi[0]);
379 io_close_buffer(&rrdpq, b);
380
381 http_fetch(id, uri, last_mod, pi[1]);
382 }
383
384 void
rrdp_http_done(unsigned int id,enum http_result res,const char * last_mod)385 rrdp_http_done(unsigned int id, enum http_result res, const char *last_mod)
386 {
387 enum rrdp_msg type = RRDP_HTTP_FIN;
388 struct ibuf *b;
389
390 /* RRDP request, relay response over to the rrdp process */
391 b = io_new_buffer();
392 io_simple_buffer(b, &type, sizeof(type));
393 io_simple_buffer(b, &id, sizeof(id));
394 io_simple_buffer(b, &res, sizeof(res));
395 io_str_buffer(b, last_mod);
396 io_close_buffer(&rrdpq, b);
397 }
398
399 /*
400 * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486.
401 * These are always relative to the directory in which "mft" sits.
402 */
403 static void
queue_add_from_mft(const struct mft * mft)404 queue_add_from_mft(const struct mft *mft)
405 {
406 size_t i;
407 struct repo *rp;
408 const struct mftfile *f;
409 char *mftaki, *nfile, *npath = NULL;
410
411 rp = repo_byid(mft->repoid);
412 for (i = 0; i < mft->filesz; i++) {
413 f = &mft->files[i];
414
415 if (f->type == RTYPE_INVALID || f->type == RTYPE_CRL)
416 continue;
417
418 if (mft->path != NULL)
419 if ((npath = strdup(mft->path)) == NULL)
420 err(1, NULL);
421 if ((nfile = strdup(f->file)) == NULL)
422 err(1, NULL);
423 if ((mftaki = strdup(mft->aki)) == NULL)
424 err(1, NULL);
425 entityq_add(npath, nfile, f->type, f->location, rp, NULL, 0,
426 mft->talid, mft->certid, mftaki);
427 }
428 }
429
430 /*
431 * Add a local file to the queue of files to fetch.
432 */
433 static void
queue_add_file(const char * file,enum rtype type,int talid)434 queue_add_file(const char *file, enum rtype type, int talid)
435 {
436 unsigned char *buf = NULL;
437 char *nfile;
438 size_t len = 0;
439
440 if (!filemode || strncmp(file, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0) {
441 buf = load_file(file, &len);
442 if (buf == NULL)
443 err(1, "%s", file);
444 }
445
446 if ((nfile = strdup(file)) == NULL)
447 err(1, NULL);
448 /* Not in a repository, so directly add to queue. */
449 entityq_add(NULL, nfile, type, DIR_UNKNOWN, NULL, buf, len, talid, 0,
450 NULL);
451 }
452
453 /*
454 * Add URIs (CER) from a TAL file, RFC 8630.
455 */
456 static void
queue_add_from_tal(struct tal * tal)457 queue_add_from_tal(struct tal *tal)
458 {
459 struct repo *repo;
460 unsigned char *data;
461 char *nfile;
462
463 assert(tal->urisz);
464
465 if ((taldescs[tal->id] = strdup(tal->descr)) == NULL)
466 err(1, NULL);
467
468 /* figure out the TA filename, must be done before repo lookup */
469 nfile = strrchr(tal->uri[0], '/');
470 assert(nfile != NULL);
471 if ((nfile = strdup(nfile + 1)) == NULL)
472 err(1, NULL);
473
474 /* Look up the repository. */
475 repo = ta_lookup(tal->id, tal);
476 if (repo == NULL) {
477 free(nfile);
478 return;
479 }
480
481 /* steal the pkey from the tal structure */
482 data = tal->pkey;
483 tal->pkey = NULL;
484 entityq_add(NULL, nfile, RTYPE_CER, DIR_UNKNOWN, repo, data,
485 tal->pkeysz, tal->id, tal->id, NULL);
486 }
487
488 /*
489 * Add a manifest (MFT) found in an X509 certificate, RFC 6487.
490 */
491 static void
queue_add_from_cert(const struct cert * cert)492 queue_add_from_cert(const struct cert *cert)
493 {
494 struct repo *repo;
495 struct fqdnlistentry *le;
496 char *nfile, *npath, *host;
497 const char *uri, *repouri, *file;
498 size_t repourisz;
499 int shortlisted = 0;
500
501 if (strncmp(cert->repo, RSYNC_PROTO, RSYNC_PROTO_LEN) != 0)
502 errx(1, "unexpected protocol");
503 host = cert->repo + 8;
504
505 LIST_FOREACH(le, &skiplist, entry) {
506 if (strncasecmp(host, le->fqdn, strcspn(host, "/")) == 0) {
507 warnx("skipping %s (listed in skiplist)", cert->repo);
508 return;
509 }
510 }
511
512 LIST_FOREACH(le, &shortlist, entry) {
513 if (strncasecmp(host, le->fqdn, strcspn(host, "/")) == 0) {
514 shortlisted = 1;
515 break;
516 }
517 }
518 if (shortlistmode && shortlisted == 0) {
519 if (verbose)
520 warnx("skipping %s (not shortlisted)", cert->repo);
521 return;
522 }
523
524 repo = repo_lookup(cert->talid, cert->repo,
525 rrdpon ? cert->notify : NULL);
526 if (repo == NULL)
527 return;
528
529 /*
530 * Figure out the cert filename and path by chopping up the
531 * MFT URI in the cert based on the repo base URI.
532 */
533 uri = cert->mft;
534 repouri = repo_uri(repo);
535 repourisz = strlen(repouri);
536 if (strncmp(repouri, cert->mft, repourisz) != 0) {
537 warnx("%s: URI %s outside of repository", repouri, uri);
538 return;
539 }
540 uri += repourisz + 1; /* skip base and '/' */
541 file = strrchr(uri, '/');
542 if (file == NULL) {
543 npath = NULL;
544 if ((nfile = strdup(uri)) == NULL)
545 err(1, NULL);
546 } else {
547 if ((npath = strndup(uri, file - uri)) == NULL)
548 err(1, NULL);
549 if ((nfile = strdup(file + 1)) == NULL)
550 err(1, NULL);
551 }
552
553 entityq_add(npath, nfile, RTYPE_MFT, DIR_UNKNOWN, repo, NULL, 0,
554 cert->talid, cert->certid, NULL);
555 }
556
557 /*
558 * Process parsed content.
559 * For non-ROAs, we grok for more data.
560 * For ROAs, we want to extract the valid info.
561 * In all cases, we gather statistics.
562 */
563 static void
entity_process(struct ibuf * b,struct stats * st,struct vrp_tree * tree,struct brk_tree * brktree,struct vap_tree * vaptree,struct vsp_tree * vsptree)564 entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree,
565 struct brk_tree *brktree, struct vap_tree *vaptree,
566 struct vsp_tree *vsptree)
567 {
568 enum rtype type;
569 struct tal *tal;
570 struct cert *cert;
571 struct mft *mft;
572 struct roa *roa;
573 struct aspa *aspa;
574 struct spl *spl;
575 struct repo *rp;
576 char *file;
577 time_t mtime;
578 unsigned int id;
579 int talid;
580 int c;
581
582 /*
583 * For most of these, we first read whether there's any content
584 * at all---this means that the syntactic parse failed (X509
585 * certificate, for example).
586 * We follow that up with whether the resources didn't parse.
587 */
588 io_read_buf(b, &type, sizeof(type));
589 io_read_buf(b, &id, sizeof(id));
590 io_read_buf(b, &talid, sizeof(talid));
591 io_read_str(b, &file);
592 io_read_buf(b, &mtime, sizeof(mtime));
593
594 /* in filemode messages can be ignored, only the accounting matters */
595 if (filemode)
596 goto done;
597
598 if (filepath_add(&fpt, file, talid, mtime) == 0) {
599 warnx("%s: File already visited", file);
600 goto done;
601 }
602
603 rp = repo_byid(id);
604 repo_stat_inc(rp, talid, type, STYPE_OK);
605 repostats_new_files_inc(rp, file);
606 switch (type) {
607 case RTYPE_TAL:
608 st->tals++;
609 tal = tal_read(b);
610 queue_add_from_tal(tal);
611 tal_free(tal);
612 break;
613 case RTYPE_CER:
614 io_read_buf(b, &c, sizeof(c));
615 if (c == 0) {
616 repo_stat_inc(rp, talid, type, STYPE_FAIL);
617 break;
618 }
619 cert = cert_read(b);
620 switch (cert->purpose) {
621 case CERT_PURPOSE_TA:
622 case CERT_PURPOSE_CA:
623 queue_add_from_cert(cert);
624 break;
625 case CERT_PURPOSE_BGPSEC_ROUTER:
626 cert_insert_brks(brktree, cert);
627 repo_stat_inc(rp, talid, type, STYPE_BGPSEC);
628 break;
629 default:
630 errx(1, "unexpected %s", purpose2str(cert->purpose));
631 break;
632 }
633 cert_free(cert);
634 break;
635 case RTYPE_MFT:
636 io_read_buf(b, &c, sizeof(c));
637 if (c == 0) {
638 repo_stat_inc(rp, talid, type, STYPE_FAIL);
639 break;
640 }
641 mft = mft_read(b);
642 queue_add_from_mft(mft);
643 mft_free(mft);
644 break;
645 case RTYPE_CRL:
646 /* CRLs are sent together with MFT and not accounted for */
647 entity_queue++;
648 break;
649 case RTYPE_ROA:
650 io_read_buf(b, &c, sizeof(c));
651 if (c == 0) {
652 repo_stat_inc(rp, talid, type, STYPE_FAIL);
653 break;
654 }
655 roa = roa_read(b);
656 if (roa->valid)
657 roa_insert_vrps(tree, roa, rp);
658 else
659 repo_stat_inc(rp, talid, type, STYPE_INVALID);
660 roa_free(roa);
661 break;
662 case RTYPE_GBR:
663 break;
664 case RTYPE_ASPA:
665 io_read_buf(b, &c, sizeof(c));
666 if (c == 0) {
667 repo_stat_inc(rp, talid, type, STYPE_FAIL);
668 break;
669 }
670 aspa = aspa_read(b);
671 if (aspa->valid)
672 aspa_insert_vaps(file, vaptree, aspa, rp);
673 else
674 repo_stat_inc(rp, talid, type, STYPE_INVALID);
675 aspa_free(aspa);
676 break;
677 case RTYPE_SPL:
678 io_read_buf(b, &c, sizeof(c));
679 if (c == 0) {
680 if (experimental)
681 repo_stat_inc(rp, talid, type, STYPE_FAIL);
682 break;
683 }
684 spl = spl_read(b);
685 if (spl->valid)
686 spl_insert_vsps(vsptree, spl, rp);
687 else
688 repo_stat_inc(rp, talid, type, STYPE_INVALID);
689 spl_free(spl);
690 break;
691 case RTYPE_TAK:
692 break;
693 case RTYPE_FILE:
694 break;
695 default:
696 warnx("%s: unknown entity type %d", file, type);
697 break;
698 }
699
700 done:
701 free(file);
702 entity_queue--;
703 }
704
705 static void
rrdp_process(struct ibuf * b)706 rrdp_process(struct ibuf *b)
707 {
708 enum rrdp_msg type;
709 enum publish_type pt;
710 struct rrdp_session *s;
711 char *uri, *last_mod, *data;
712 char hash[SHA256_DIGEST_LENGTH];
713 size_t dsz;
714 unsigned int id;
715 int ok;
716
717 io_read_buf(b, &type, sizeof(type));
718 io_read_buf(b, &id, sizeof(id));
719
720 switch (type) {
721 case RRDP_END:
722 io_read_buf(b, &ok, sizeof(ok));
723 rrdp_finish(id, ok);
724 break;
725 case RRDP_HTTP_REQ:
726 io_read_str(b, &uri);
727 io_read_str(b, &last_mod);
728 rrdp_http_fetch(id, uri, last_mod);
729 break;
730 case RRDP_SESSION:
731 s = rrdp_session_read(b);
732 rrdp_session_save(id, s);
733 rrdp_session_free(s);
734 break;
735 case RRDP_FILE:
736 io_read_buf(b, &pt, sizeof(pt));
737 if (pt != PUB_ADD)
738 io_read_buf(b, &hash, sizeof(hash));
739 io_read_str(b, &uri);
740 io_read_buf_alloc(b, (void **)&data, &dsz);
741
742 ok = rrdp_handle_file(id, pt, uri, hash, sizeof(hash),
743 data, dsz);
744 rrdp_file_resp(id, ok);
745
746 free(uri);
747 free(data);
748 break;
749 case RRDP_CLEAR:
750 rrdp_clear(id);
751 break;
752 default:
753 errx(1, "unexpected rrdp response");
754 }
755 }
756
757 static void
sum_stats(const struct repo * rp,const struct repotalstats * in,void * arg)758 sum_stats(const struct repo *rp, const struct repotalstats *in, void *arg)
759 {
760 struct repotalstats *out = arg;
761
762 out->mfts += in->mfts;
763 out->mfts_fail += in->mfts_fail;
764 out->certs += in->certs;
765 out->certs_fail += in->certs_fail;
766 out->roas += in->roas;
767 out->roas_fail += in->roas_fail;
768 out->roas_invalid += in->roas_invalid;
769 out->aspas += in->aspas;
770 out->aspas_fail += in->aspas_fail;
771 out->aspas_invalid += in->aspas_invalid;
772 out->brks += in->brks;
773 out->crls += in->crls;
774 out->gbrs += in->gbrs;
775 out->taks += in->taks;
776 out->vrps += in->vrps;
777 out->vrps_uniqs += in->vrps_uniqs;
778 out->vaps += in->vaps;
779 out->vaps_uniqs += in->vaps_uniqs;
780 out->vaps_pas += in->vaps_pas;
781 out->vaps_overflowed += in->vaps_overflowed;
782 out->spls += in->spls;
783 out->spls_fail += in->spls_fail;
784 out->spls_invalid += in->spls_invalid;
785 out->vsps += in->vsps;
786 out->vsps_uniqs += in->vsps_uniqs;
787 }
788
789 static void
sum_repostats(const struct repo * rp,const struct repostats * in,void * arg)790 sum_repostats(const struct repo *rp, const struct repostats *in, void *arg)
791 {
792 struct repostats *out = arg;
793
794 out->del_files += in->del_files;
795 out->extra_files += in->extra_files;
796 out->del_extra_files += in->del_extra_files;
797 out->del_dirs += in->del_dirs;
798 out->new_files += in->new_files;
799 timespecadd(&in->sync_time, &out->sync_time, &out->sync_time);
800 }
801
802 /*
803 * Assign filenames ending in ".tal" in "/etc/rpki" into "tals",
804 * returning the number of files found and filled-in.
805 * This may be zero.
806 * Don't exceed "max" filenames.
807 */
808 static int
tal_load_default(void)809 tal_load_default(void)
810 {
811 static const char *confdir = "/etc/rpki";
812 int s = 0;
813 char *path;
814 DIR *dirp;
815 struct dirent *dp;
816
817 dirp = opendir(confdir);
818 if (dirp == NULL)
819 err(1, "open %s", confdir);
820 while ((dp = readdir(dirp)) != NULL) {
821 if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
822 continue;
823 if (s >= TALSZ_MAX)
824 err(1, "too many tal files found in %s",
825 confdir);
826 if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1)
827 err(1, NULL);
828 tals[s++] = path;
829 }
830 closedir(dirp);
831 return s;
832 }
833
834 /*
835 * Load the list of FQDNs from the skiplist which are to be distrusted.
836 * Return 0 on success.
837 */
838 static void
load_skiplist(const char * slf)839 load_skiplist(const char *slf)
840 {
841 struct fqdnlistentry *le;
842 FILE *fp;
843 char *line = NULL;
844 size_t linesize = 0, linelen;
845
846 if ((fp = fopen(slf, "r")) == NULL) {
847 if (errno == ENOENT && strcmp(slf, DEFAULT_SKIPLIST_FILE) == 0)
848 return;
849 err(1, "failed to open %s", slf);
850 }
851
852 while (getline(&line, &linesize, fp) != -1) {
853 /* just eat comment lines or empty lines*/
854 if (line[0] == '#' || line[0] == '\n')
855 continue;
856
857 if (line[0] == ' ' || line[0] == '\t')
858 errx(1, "invalid entry in skiplist: %s", line);
859
860 /*
861 * Ignore anything after comment sign, whitespaces,
862 * also chop off LF or CR.
863 */
864 linelen = strcspn(line, " #\r\n\t");
865 line[linelen] = '\0';
866
867 if (!valid_uri(line, linelen, NULL))
868 errx(1, "invalid entry in skiplist: %s", line);
869
870 if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
871 err(1, NULL);
872 if ((le->fqdn = strdup(line)) == NULL)
873 err(1, NULL);
874
875 LIST_INSERT_HEAD(&skiplist, le, entry);
876 stats.skiplistentries++;
877 }
878
879 fclose(fp);
880 free(line);
881 }
882
883 /*
884 * Load shortlist entries.
885 */
886 static void
load_shortlist(const char * fqdn)887 load_shortlist(const char *fqdn)
888 {
889 struct fqdnlistentry *le;
890
891 if (!valid_uri(fqdn, strlen(fqdn), NULL))
892 errx(1, "invalid fqdn passed to -q: %s", fqdn);
893
894 if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
895 err(1, NULL);
896
897 if ((le->fqdn = strdup(fqdn)) == NULL)
898 err(1, NULL);
899
900 LIST_INSERT_HEAD(&shortlist, le, entry);
901 }
902
903 static void
check_fs_size(int fd,const char * cachedir)904 check_fs_size(int fd, const char *cachedir)
905 {
906 struct statvfs fs;
907 unsigned long long minsize = 500 * 1024 * 1024;
908 unsigned long long minnode = 300 * 1000;
909
910 if (fstatvfs(fd, &fs) == -1)
911 err(1, "statfs %s", cachedir);
912
913 if (fs.f_bavail < minsize / fs.f_frsize ||
914 (fs.f_ffree > 0 && fs.f_favail < minnode)) {
915 fprintf(stderr, "WARNING: rpki-client may need more than "
916 "the available disk space\n"
917 "on the file-system holding %s.\n", cachedir);
918 fprintf(stderr, "available space: %llukB, "
919 "suggested minimum %llukB\n",
920 (unsigned long long)fs.f_bavail * fs.f_frsize / 1024,
921 minsize / 1024);
922 fprintf(stderr, "available inodes: %llu, "
923 "suggested minimum: %llu\n\n",
924 (unsigned long long)fs.f_favail, minnode);
925 fflush(stderr);
926 }
927 }
928
929 static pid_t
process_start(const char * title,int * fd)930 process_start(const char *title, int *fd)
931 {
932 int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
933 pid_t pid;
934 int pair[2];
935
936 if (socketpair(AF_UNIX, fl, 0, pair) == -1)
937 err(1, "socketpair");
938 if ((pid = fork()) == -1)
939 err(1, "fork");
940
941 if (pid == 0) {
942 setproctitle("%s", title);
943 /* change working directory to the cache directory */
944 if (fchdir(cachefd) == -1)
945 err(1, "fchdir");
946 if (!filemode && timeout > 0)
947 alarm(timeout);
948 close(pair[1]);
949 *fd = pair[0];
950 } else {
951 close(pair[0]);
952 *fd = pair[1];
953 }
954 return pid;
955 }
956
957 void
suicide(int sig)958 suicide(int sig __attribute__((unused)))
959 {
960 killme = 1;
961 }
962
963 #define NPFD 4
964
965 int
main(int argc,char * argv[])966 main(int argc, char *argv[])
967 {
968 int rc, c, i, st, proc, rsync, http, rrdp, hangup = 0;
969 pid_t pid, procpid, rsyncpid, httppid, rrdppid;
970 struct pollfd pfd[NPFD];
971 struct msgbuf *queues[NPFD];
972 struct ibuf *b, *httpbuf = NULL, *procbuf = NULL;
973 struct ibuf *rrdpbuf = NULL, *rsyncbuf = NULL;
974 char *rsync_prog = "openrsync";
975 char *bind_addr = NULL;
976 const char *cachedir = NULL, *outputdir = NULL;
977 const char *errs, *name;
978 const char *skiplistfile = NULL;
979 struct vrp_tree vrps = RB_INITIALIZER(&vrps);
980 struct vsp_tree vsps = RB_INITIALIZER(&vsps);
981 struct brk_tree brks = RB_INITIALIZER(&brks);
982 struct vap_tree vaps = RB_INITIALIZER(&vaps);
983 struct rusage ru;
984 struct timespec start_time, now_time;
985
986 clock_gettime(CLOCK_MONOTONIC, &start_time);
987
988 /* If started as root, priv-drop to _rpki-client */
989 if (getuid() == 0) {
990 struct passwd *pw;
991
992 pw = getpwnam("_rpki-client");
993 if (!pw)
994 errx(1, "no _rpki-client user to revoke to");
995 if (setgroups(1, &pw->pw_gid) == -1 ||
996 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
997 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
998 err(1, "unable to revoke privs");
999 }
1000 cachedir = RPKI_PATH_BASE_DIR;
1001 outputdir = RPKI_PATH_OUT_DIR;
1002 repo_timeout = timeout / 4;
1003 skiplistfile = DEFAULT_SKIPLIST_FILE;
1004
1005 if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd "
1006 "proc exec unveil", NULL) == -1)
1007 err(1, "pledge");
1008
1009 while ((c = getopt(argc, argv, "Ab:Bcd:e:fH:jmnoP:rRs:S:t:T:vVx")) != -1)
1010 switch (c) {
1011 case 'A':
1012 excludeaspa = 1;
1013 break;
1014 case 'b':
1015 bind_addr = optarg;
1016 break;
1017 case 'B':
1018 outformats |= FORMAT_BIRD;
1019 break;
1020 case 'c':
1021 outformats |= FORMAT_CSV;
1022 break;
1023 case 'd':
1024 cachedir = optarg;
1025 break;
1026 case 'e':
1027 rsync_prog = optarg;
1028 break;
1029 case 'f':
1030 filemode = 1;
1031 noop = 1;
1032 break;
1033 case 'H':
1034 shortlistmode = 1;
1035 load_shortlist(optarg);
1036 break;
1037 case 'j':
1038 outformats |= FORMAT_JSON;
1039 break;
1040 case 'm':
1041 outformats |= FORMAT_OMETRIC;
1042 break;
1043 case 'n':
1044 noop = 1;
1045 break;
1046 case 'o':
1047 outformats |= FORMAT_OPENBGPD;
1048 break;
1049 case 'P':
1050 evaluation_time = strtonum(optarg, X509_TIME_MIN + 1,
1051 X509_TIME_MAX, &errs);
1052 if (errs)
1053 errx(1, "-P: time in seconds %s", errs);
1054 break;
1055 case 'R':
1056 rrdpon = 0;
1057 break;
1058 case 'r': /* Remove after OpenBSD 7.3 */
1059 rrdpon = 1;
1060 break;
1061 case 's':
1062 timeout = strtonum(optarg, 0, 24*60*60, &errs);
1063 if (errs)
1064 errx(1, "-s: %s", errs);
1065 if (timeout == 0)
1066 repo_timeout = 24*60*60;
1067 else
1068 repo_timeout = timeout / 4;
1069 break;
1070 case 'S':
1071 skiplistfile = optarg;
1072 break;
1073 case 't':
1074 if (talsz >= TALSZ_MAX)
1075 err(1, "too many tal files specified");
1076 tals[talsz++] = optarg;
1077 break;
1078 case 'T':
1079 bird_tablename = optarg;
1080 break;
1081 case 'v':
1082 verbose++;
1083 break;
1084 case 'V':
1085 fprintf(stderr, "rpki-client %s\n", RPKI_VERSION);
1086 return 0;
1087 case 'x':
1088 experimental = 1;
1089 break;
1090 default:
1091 goto usage;
1092 }
1093
1094 argv += optind;
1095 argc -= optind;
1096
1097 if (!filemode) {
1098 if (argc == 1)
1099 outputdir = argv[0];
1100 else if (argc > 1)
1101 goto usage;
1102
1103 if (outputdir == NULL) {
1104 warnx("output directory required");
1105 goto usage;
1106 }
1107 } else {
1108 if (argc == 0)
1109 goto usage;
1110 outputdir = NULL;
1111 }
1112
1113 if (cachedir == NULL) {
1114 warnx("cache directory required");
1115 goto usage;
1116 }
1117
1118 signal(SIGPIPE, SIG_IGN);
1119
1120 if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1)
1121 err(1, "cache directory %s", cachedir);
1122 if (outputdir != NULL) {
1123 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1)
1124 err(1, "output directory %s", outputdir);
1125 if (outformats == 0)
1126 outformats = FORMAT_OPENBGPD;
1127 }
1128
1129 check_fs_size(cachefd, cachedir);
1130
1131 if (talsz == 0)
1132 talsz = tal_load_default();
1133 if (talsz == 0)
1134 err(1, "no TAL files found in %s", "/etc/rpki");
1135
1136 /* Load optional constraint files sitting next to the TALs. */
1137 constraints_load();
1138
1139 /*
1140 * Create the file reader as a jailed child process.
1141 * It will be responsible for reading all of the files (ROAs,
1142 * manifests, certificates, etc.) and returning contents.
1143 */
1144
1145 procpid = process_start("parser", &proc);
1146 if (procpid == 0) {
1147 if (!filemode)
1148 proc_parser(proc);
1149 else
1150 proc_filemode(proc);
1151 }
1152
1153 /* Constraints are only needed in the filemode and parser processes. */
1154 constraints_unload();
1155
1156 /*
1157 * Create a process that will do the rsync'ing.
1158 * This process is responsible for making sure that all the
1159 * repositories referenced by a certificate manifest (or the
1160 * TAL) exists and has been downloaded.
1161 */
1162
1163 if (!noop) {
1164 rsyncpid = process_start("rsync", &rsync);
1165 if (rsyncpid == 0) {
1166 close(proc);
1167 proc_rsync(rsync_prog, bind_addr, rsync);
1168 }
1169 } else {
1170 rsync = -1;
1171 rsyncpid = -1;
1172 }
1173
1174 /*
1175 * Create a process that will fetch data via https.
1176 * With every request the http process receives a file descriptor
1177 * where the data should be written to.
1178 */
1179
1180 if (!noop && rrdpon) {
1181 httppid = process_start("http", &http);
1182
1183 if (httppid == 0) {
1184 close(proc);
1185 close(rsync);
1186 proc_http(bind_addr, http);
1187 }
1188 } else {
1189 http = -1;
1190 httppid = -1;
1191 }
1192
1193 /*
1194 * Create a process that will process RRDP.
1195 * The rrdp process requires the http process to fetch the various
1196 * XML files and does this via the main process.
1197 */
1198
1199 if (!noop && rrdpon) {
1200 rrdppid = process_start("rrdp", &rrdp);
1201 if (rrdppid == 0) {
1202 close(proc);
1203 close(rsync);
1204 close(http);
1205 proc_rrdp(rrdp);
1206 }
1207 } else {
1208 rrdp = -1;
1209 rrdppid = -1;
1210 }
1211
1212 if (!filemode && timeout > 0) {
1213 /*
1214 * Commit suicide eventually
1215 * cron will normally start a new one
1216 */
1217 alarm(timeout);
1218 signal(SIGALRM, suicide);
1219
1220 /* give up a bit before the hard timeout and try to finish up */
1221 if (!noop)
1222 deadline = getmonotime() + timeout - repo_timeout / 2;
1223 }
1224
1225 if (pledge("stdio rpath wpath cpath fattr sendfd unveil", NULL) == -1)
1226 err(1, "pledge");
1227
1228 msgbuf_init(&procq);
1229 msgbuf_init(&rsyncq);
1230 msgbuf_init(&httpq);
1231 msgbuf_init(&rrdpq);
1232 procq.fd = proc;
1233 rsyncq.fd = rsync;
1234 httpq.fd = http;
1235 rrdpq.fd = rrdp;
1236
1237 /*
1238 * The main process drives the top-down scan to leaf ROAs using
1239 * data downloaded by the rsync process and parsed by the
1240 * parsing process.
1241 */
1242
1243 pfd[0].fd = proc;
1244 queues[0] = &procq;
1245 pfd[1].fd = rsync;
1246 queues[1] = &rsyncq;
1247 pfd[2].fd = http;
1248 queues[2] = &httpq;
1249 pfd[3].fd = rrdp;
1250 queues[3] = &rrdpq;
1251
1252 load_skiplist(skiplistfile);
1253
1254 /*
1255 * Prime the process with our TAL files.
1256 * These will (hopefully) contain links to manifests and we
1257 * can get the ball rolling.
1258 */
1259
1260 for (i = 0; i < talsz; i++)
1261 queue_add_file(tals[i], RTYPE_TAL, i);
1262
1263 if (filemode) {
1264 while (*argv != NULL)
1265 queue_add_file(*argv++, RTYPE_FILE, 0);
1266
1267 if (unveil(cachedir, "r") == -1)
1268 err(1, "unveil cachedir");
1269 } else {
1270 if (unveil(outputdir, "rwc") == -1)
1271 err(1, "unveil outputdir");
1272 if (unveil(cachedir, "rwc") == -1)
1273 err(1, "unveil cachedir");
1274 }
1275 if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1)
1276 err(1, "unveil");
1277
1278 /* change working directory to the cache directory */
1279 if (fchdir(cachefd) == -1)
1280 err(1, "fchdir");
1281
1282 while (entity_queue > 0 && !killme) {
1283 int polltim;
1284
1285 for (i = 0; i < NPFD; i++) {
1286 pfd[i].events = POLLIN;
1287 if (queues[i]->queued)
1288 pfd[i].events |= POLLOUT;
1289 }
1290
1291 polltim = repo_check_timeout(INFTIM);
1292
1293 if (poll(pfd, NPFD, polltim) == -1) {
1294 if (errno == EINTR)
1295 continue;
1296 err(1, "poll");
1297 }
1298
1299 for (i = 0; i < NPFD; i++) {
1300 if (pfd[i].revents & (POLLERR|POLLNVAL)) {
1301 warnx("poll[%d]: bad fd", i);
1302 hangup = 1;
1303 }
1304 if (pfd[i].revents & POLLHUP)
1305 hangup = 1;
1306 if (pfd[i].revents & POLLOUT) {
1307 switch (msgbuf_write(queues[i])) {
1308 case 0:
1309 warnx("write[%d]: "
1310 "connection closed", i);
1311 hangup = 1;
1312 break;
1313 case -1:
1314 warn("write[%d]", i);
1315 hangup = 1;
1316 break;
1317 }
1318 }
1319 }
1320 if (hangup)
1321 break;
1322
1323 /*
1324 * Check the rsync and http process.
1325 * This means that one of our modules has completed
1326 * downloading and we can flush the module requests into
1327 * the parser process.
1328 */
1329
1330 if ((pfd[1].revents & POLLIN)) {
1331 b = io_buf_read(rsync, &rsyncbuf);
1332 if (b != NULL) {
1333 unsigned int id;
1334 int ok;
1335
1336 io_read_buf(b, &id, sizeof(id));
1337 io_read_buf(b, &ok, sizeof(ok));
1338 rsync_finish(id, ok);
1339 ibuf_free(b);
1340 }
1341 }
1342
1343 if ((pfd[2].revents & POLLIN)) {
1344 b = io_buf_read(http, &httpbuf);
1345 if (b != NULL) {
1346 unsigned int id;
1347 enum http_result res;
1348 char *last_mod;
1349
1350 io_read_buf(b, &id, sizeof(id));
1351 io_read_buf(b, &res, sizeof(res));
1352 io_read_str(b, &last_mod);
1353 http_finish(id, res, last_mod);
1354 free(last_mod);
1355 ibuf_free(b);
1356 }
1357 }
1358
1359 /*
1360 * Handle RRDP requests here.
1361 */
1362 if ((pfd[3].revents & POLLIN)) {
1363 b = io_buf_read(rrdp, &rrdpbuf);
1364 if (b != NULL) {
1365 rrdp_process(b);
1366 ibuf_free(b);
1367 }
1368 }
1369
1370 /*
1371 * The parser has finished something for us.
1372 * Dequeue these one by one.
1373 */
1374
1375 if ((pfd[0].revents & POLLIN)) {
1376 b = io_buf_read(proc, &procbuf);
1377 if (b != NULL) {
1378 entity_process(b, &stats, &vrps, &brks, &vaps,
1379 &vsps);
1380 ibuf_free(b);
1381 }
1382 }
1383 }
1384
1385 signal(SIGALRM, SIG_DFL);
1386 if (killme) {
1387 syslog(LOG_CRIT|LOG_DAEMON,
1388 "excessive runtime (%d seconds), giving up", timeout);
1389 errx(1, "excessive runtime (%d seconds), giving up", timeout);
1390 }
1391
1392 /*
1393 * For clean-up, close the input for the parser and rsync
1394 * process.
1395 * This will cause them to exit, then we reap them.
1396 */
1397
1398 close(proc);
1399 close(rsync);
1400 close(http);
1401 close(rrdp);
1402
1403 rc = 0;
1404 for (;;) {
1405 pid = waitpid(WAIT_ANY, &st, 0);
1406 if (pid == -1) {
1407 if (errno == EINTR)
1408 continue;
1409 if (errno == ECHILD)
1410 break;
1411 err(1, "wait");
1412 }
1413
1414 if (pid == procpid)
1415 name = "parser";
1416 else if (pid == rsyncpid)
1417 name = "rsync";
1418 else if (pid == httppid)
1419 name = "http";
1420 else if (pid == rrdppid)
1421 name = "rrdp";
1422 else
1423 name = "unknown";
1424
1425 if (WIFSIGNALED(st)) {
1426 warnx("%s terminated signal %d", name, WTERMSIG(st));
1427 rc = 1;
1428 } else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
1429 warnx("%s process exited abnormally", name);
1430 rc = 1;
1431 }
1432 }
1433
1434 /* processing did not finish because of error */
1435 if (entity_queue != 0)
1436 errx(1, "not all files processed, giving up");
1437
1438 /* if processing in filemode the process is done, no cleanup */
1439 if (filemode)
1440 return rc;
1441
1442 logx("all files parsed: generating output");
1443
1444 if (!noop)
1445 repo_cleanup(&fpt, cachefd);
1446
1447 clock_gettime(CLOCK_MONOTONIC, &now_time);
1448 timespecsub(&now_time, &start_time, &stats.elapsed_time);
1449 if (getrusage(RUSAGE_SELF, &ru) == 0) {
1450 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &stats.user_time);
1451 TIMEVAL_TO_TIMESPEC(&ru.ru_stime, &stats.system_time);
1452 }
1453 if (getrusage(RUSAGE_CHILDREN, &ru) == 0) {
1454 struct timespec ts;
1455
1456 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &ts);
1457 timespecadd(&stats.user_time, &ts, &stats.user_time);
1458 TIMEVAL_TO_TIMESPEC(&ru.ru_stime, &ts);
1459 timespecadd(&stats.system_time, &ts, &stats.system_time);
1460 }
1461
1462 /* change working directory to the output directory */
1463 if (fchdir(outdirfd) == -1)
1464 err(1, "fchdir output dir");
1465
1466 for (i = 0; i < talsz; i++) {
1467 repo_tal_stats_collect(sum_stats, i, &talstats[i]);
1468 repo_tal_stats_collect(sum_stats, i, &stats.repo_tal_stats);
1469 }
1470 repo_stats_collect(sum_repostats, &stats.repo_stats);
1471
1472 if (outputfiles(&vrps, &brks, &vaps, &vsps, &stats))
1473 rc = 1;
1474
1475 printf("Processing time %lld seconds "
1476 "(%lld seconds user, %lld seconds system)\n",
1477 (long long)stats.elapsed_time.tv_sec,
1478 (long long)stats.user_time.tv_sec,
1479 (long long)stats.system_time.tv_sec);
1480 printf("Skiplist entries: %u\n", stats.skiplistentries);
1481 printf("Route Origin Authorizations: %u (%u failed parse, %u "
1482 "invalid)\n", stats.repo_tal_stats.roas,
1483 stats.repo_tal_stats.roas_fail,
1484 stats.repo_tal_stats.roas_invalid);
1485 printf("AS Provider Attestations: %u (%u failed parse, %u "
1486 "invalid)\n", stats.repo_tal_stats.aspas,
1487 stats.repo_tal_stats.aspas_fail,
1488 stats.repo_tal_stats.aspas_invalid);
1489 printf("Signed Prefix Lists: %u (%u failed parse, %u invalid)\n",
1490 stats.repo_tal_stats.spls, stats.repo_tal_stats.spls_fail,
1491 stats.repo_tal_stats.spls_invalid);
1492 printf("BGPsec Router Certificates: %u\n", stats.repo_tal_stats.brks);
1493 printf("Certificates: %u (%u invalid)\n",
1494 stats.repo_tal_stats.certs, stats.repo_tal_stats.certs_fail);
1495 printf("Trust Anchor Locators: %u (%u invalid)\n",
1496 stats.tals, talsz - stats.tals);
1497 printf("Manifests: %u (%u failed parse)\n",
1498 stats.repo_tal_stats.mfts, stats.repo_tal_stats.mfts_fail);
1499 printf("Certificate revocation lists: %u\n", stats.repo_tal_stats.crls);
1500 printf("Ghostbuster records: %u\n", stats.repo_tal_stats.gbrs);
1501 printf("Trust Anchor Keys: %u\n", stats.repo_tal_stats.taks);
1502 printf("Repositories: %u\n", stats.repos);
1503 printf("New files moved into validated cache: %u\n",
1504 stats.repo_stats.new_files);
1505 printf("Cleanup: removed %u files, %u directories\n"
1506 "Repository cleanup: kept %u and removed %u superfluous files\n",
1507 stats.repo_stats.del_files, stats.repo_stats.del_dirs,
1508 stats.repo_stats.extra_files, stats.repo_stats.del_extra_files);
1509 printf("VRP Entries: %u (%u unique)\n", stats.repo_tal_stats.vrps,
1510 stats.repo_tal_stats.vrps_uniqs);
1511 printf("VAP Entries: %u (%u unique, %u overflowed)\n",
1512 stats.repo_tal_stats.vaps, stats.repo_tal_stats.vaps_uniqs,
1513 stats.repo_tal_stats.vaps_overflowed);
1514 printf("VSP Entries: %u (%u unique)\n", stats.repo_tal_stats.vsps,
1515 stats.repo_tal_stats.vsps_uniqs);
1516
1517 /* Memory cleanup. */
1518 repo_free();
1519
1520 return rc;
1521
1522 usage:
1523 fprintf(stderr,
1524 "usage: rpki-client [-ABcjmnoRrVvx] [-b sourceaddr] [-d cachedir]"
1525 " [-e rsync_prog]\n"
1526 " [-H fqdn] [-P epoch] [-S skiplist] [-s timeout]"
1527 " [-T table]\n"
1528 " [-t tal] [outputdir]\n"
1529 " rpki-client [-Vv] [-d cachedir] [-j] [-t tal] -f file ..."
1530 "\n");
1531 return 1;
1532 }
1533