1 /* $OpenBSD: main.c,v 1.269 2024/11/02 12:30:28 job 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 ok = 1;
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_valid(&fpt, file, talid)) {
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, &ok, sizeof(ok));
615 if (ok == 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, &ok, sizeof(ok));
637 if (ok == 0) {
638 repo_stat_inc(rp, talid, type, STYPE_FAIL);
639 break;
640 }
641 mft = mft_read(b);
642 if (mft->seqnum_gap)
643 repo_stat_inc(rp, talid, type, STYPE_SEQNUM_GAP);
644 queue_add_from_mft(mft);
645 mft_free(mft);
646 break;
647 case RTYPE_CRL:
648 /* CRLs are sent together with MFT and not accounted for */
649 entity_queue++;
650 break;
651 case RTYPE_ROA:
652 io_read_buf(b, &ok, sizeof(ok));
653 if (ok == 0) {
654 repo_stat_inc(rp, talid, type, STYPE_FAIL);
655 break;
656 }
657 roa = roa_read(b);
658 if (roa->valid)
659 roa_insert_vrps(tree, roa, rp);
660 else
661 repo_stat_inc(rp, talid, type, STYPE_INVALID);
662 roa_free(roa);
663 break;
664 case RTYPE_GBR:
665 break;
666 case RTYPE_ASPA:
667 io_read_buf(b, &ok, sizeof(ok));
668 if (ok == 0) {
669 repo_stat_inc(rp, talid, type, STYPE_FAIL);
670 break;
671 }
672 aspa = aspa_read(b);
673 if (aspa->valid)
674 aspa_insert_vaps(file, vaptree, aspa, rp);
675 else
676 repo_stat_inc(rp, talid, type, STYPE_INVALID);
677 aspa_free(aspa);
678 break;
679 case RTYPE_SPL:
680 io_read_buf(b, &ok, sizeof(ok));
681 if (ok == 0) {
682 if (experimental)
683 repo_stat_inc(rp, talid, type, STYPE_FAIL);
684 break;
685 }
686 spl = spl_read(b);
687 if (spl->valid)
688 spl_insert_vsps(vsptree, spl, rp);
689 else
690 repo_stat_inc(rp, talid, type, STYPE_INVALID);
691 spl_free(spl);
692 break;
693 case RTYPE_TAK:
694 break;
695 case RTYPE_FILE:
696 break;
697 default:
698 warnx("%s: unknown entity type %d", file, type);
699 break;
700 }
701
702 if (filepath_add(&fpt, file, talid, mtime, ok) == 0)
703 errx(1, "%s: File already in tree", file);
704
705 done:
706 free(file);
707 entity_queue--;
708 }
709
710 static void
rrdp_process(struct ibuf * b)711 rrdp_process(struct ibuf *b)
712 {
713 enum rrdp_msg type;
714 enum publish_type pt;
715 struct rrdp_session *s;
716 char *uri, *last_mod, *data;
717 char hash[SHA256_DIGEST_LENGTH];
718 size_t dsz;
719 unsigned int id;
720 int ok;
721
722 io_read_buf(b, &type, sizeof(type));
723 io_read_buf(b, &id, sizeof(id));
724
725 switch (type) {
726 case RRDP_END:
727 io_read_buf(b, &ok, sizeof(ok));
728 rrdp_finish(id, ok);
729 break;
730 case RRDP_HTTP_REQ:
731 io_read_str(b, &uri);
732 io_read_str(b, &last_mod);
733 rrdp_http_fetch(id, uri, last_mod);
734 break;
735 case RRDP_SESSION:
736 s = rrdp_session_read(b);
737 rrdp_session_save(id, s);
738 rrdp_session_free(s);
739 break;
740 case RRDP_FILE:
741 io_read_buf(b, &pt, sizeof(pt));
742 if (pt != PUB_ADD)
743 io_read_buf(b, &hash, sizeof(hash));
744 io_read_str(b, &uri);
745 io_read_buf_alloc(b, (void **)&data, &dsz);
746
747 ok = rrdp_handle_file(id, pt, uri, hash, sizeof(hash),
748 data, dsz);
749 rrdp_file_resp(id, ok);
750
751 free(uri);
752 free(data);
753 break;
754 case RRDP_CLEAR:
755 rrdp_clear(id);
756 break;
757 default:
758 errx(1, "unexpected rrdp response");
759 }
760 }
761
762 static void
sum_stats(const struct repo * rp,const struct repotalstats * in,void * arg)763 sum_stats(const struct repo *rp, const struct repotalstats *in, void *arg)
764 {
765 struct repotalstats *out = arg;
766
767 out->mfts += in->mfts;
768 out->mfts_fail += in->mfts_fail;
769 out->mfts_gap += in->mfts_gap;
770 out->certs += in->certs;
771 out->certs_fail += in->certs_fail;
772 out->roas += in->roas;
773 out->roas_fail += in->roas_fail;
774 out->roas_invalid += in->roas_invalid;
775 out->aspas += in->aspas;
776 out->aspas_fail += in->aspas_fail;
777 out->aspas_invalid += in->aspas_invalid;
778 out->brks += in->brks;
779 out->crls += in->crls;
780 out->gbrs += in->gbrs;
781 out->taks += in->taks;
782 out->vrps += in->vrps;
783 out->vrps_uniqs += in->vrps_uniqs;
784 out->vaps += in->vaps;
785 out->vaps_uniqs += in->vaps_uniqs;
786 out->vaps_pas += in->vaps_pas;
787 out->vaps_overflowed += in->vaps_overflowed;
788 out->spls += in->spls;
789 out->spls_fail += in->spls_fail;
790 out->spls_invalid += in->spls_invalid;
791 out->vsps += in->vsps;
792 out->vsps_uniqs += in->vsps_uniqs;
793 }
794
795 static void
sum_repostats(const struct repo * rp,const struct repostats * in,void * arg)796 sum_repostats(const struct repo *rp, const struct repostats *in, void *arg)
797 {
798 struct repostats *out = arg;
799
800 out->del_files += in->del_files;
801 out->extra_files += in->extra_files;
802 out->del_extra_files += in->del_extra_files;
803 out->del_dirs += in->del_dirs;
804 out->new_files += in->new_files;
805 timespecadd(&in->sync_time, &out->sync_time, &out->sync_time);
806 }
807
808 /*
809 * Assign filenames ending in ".tal" in "/etc/rpki" into "tals",
810 * returning the number of files found and filled-in.
811 * This may be zero.
812 * Don't exceed "max" filenames.
813 */
814 static int
tal_load_default(void)815 tal_load_default(void)
816 {
817 static const char *confdir = "/etc/rpki";
818 int s = 0;
819 char *path;
820 DIR *dirp;
821 struct dirent *dp;
822
823 dirp = opendir(confdir);
824 if (dirp == NULL)
825 err(1, "open %s", confdir);
826 while ((dp = readdir(dirp)) != NULL) {
827 if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH)
828 continue;
829 if (s >= TALSZ_MAX)
830 err(1, "too many tal files found in %s",
831 confdir);
832 if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1)
833 err(1, NULL);
834 tals[s++] = path;
835 }
836 closedir(dirp);
837 return s;
838 }
839
840 /*
841 * Load the list of FQDNs from the skiplist which are to be distrusted.
842 * Return 0 on success.
843 */
844 static void
load_skiplist(const char * slf)845 load_skiplist(const char *slf)
846 {
847 struct fqdnlistentry *le;
848 FILE *fp;
849 char *line = NULL;
850 size_t linesize = 0, linelen;
851
852 if ((fp = fopen(slf, "r")) == NULL) {
853 if (errno == ENOENT && strcmp(slf, DEFAULT_SKIPLIST_FILE) == 0)
854 return;
855 err(1, "failed to open %s", slf);
856 }
857
858 while (getline(&line, &linesize, fp) != -1) {
859 /* just eat comment lines or empty lines*/
860 if (line[0] == '#' || line[0] == '\n')
861 continue;
862
863 if (line[0] == ' ' || line[0] == '\t')
864 errx(1, "invalid entry in skiplist: %s", line);
865
866 /*
867 * Ignore anything after comment sign, whitespaces,
868 * also chop off LF or CR.
869 */
870 linelen = strcspn(line, " #\r\n\t");
871 line[linelen] = '\0';
872
873 if (!valid_uri(line, linelen, NULL))
874 errx(1, "invalid entry in skiplist: %s", line);
875
876 if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
877 err(1, NULL);
878 if ((le->fqdn = strdup(line)) == NULL)
879 err(1, NULL);
880
881 LIST_INSERT_HEAD(&skiplist, le, entry);
882 stats.skiplistentries++;
883 }
884 if (ferror(fp))
885 err(1, "error reading %s", slf);
886
887 fclose(fp);
888 free(line);
889 }
890
891 /*
892 * Load shortlist entries.
893 */
894 static void
load_shortlist(const char * fqdn)895 load_shortlist(const char *fqdn)
896 {
897 struct fqdnlistentry *le;
898
899 if (!valid_uri(fqdn, strlen(fqdn), NULL))
900 errx(1, "invalid fqdn passed to -q: %s", fqdn);
901
902 if ((le = malloc(sizeof(struct fqdnlistentry))) == NULL)
903 err(1, NULL);
904
905 if ((le->fqdn = strdup(fqdn)) == NULL)
906 err(1, NULL);
907
908 LIST_INSERT_HEAD(&shortlist, le, entry);
909 }
910
911 static void
check_fs_size(int fd,const char * cachedir)912 check_fs_size(int fd, const char *cachedir)
913 {
914 struct statvfs fs;
915 unsigned long long minsize = 500 * 1024 * 1024;
916 unsigned long long minnode = 300 * 1000;
917
918 if (fstatvfs(fd, &fs) == -1)
919 err(1, "statfs %s", cachedir);
920
921 if (fs.f_bavail < minsize / fs.f_frsize ||
922 (fs.f_ffree > 0 && fs.f_favail < minnode)) {
923 fprintf(stderr, "WARNING: rpki-client may need more than "
924 "the available disk space\n"
925 "on the file-system holding %s.\n", cachedir);
926 fprintf(stderr, "available space: %llukB, "
927 "suggested minimum %llukB\n",
928 (unsigned long long)fs.f_bavail * fs.f_frsize / 1024,
929 minsize / 1024);
930 fprintf(stderr, "available inodes: %llu, "
931 "suggested minimum: %llu\n\n",
932 (unsigned long long)fs.f_favail, minnode);
933 fflush(stderr);
934 }
935 }
936
937 static pid_t
process_start(const char * title,int * fd)938 process_start(const char *title, int *fd)
939 {
940 int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK;
941 pid_t pid;
942 int pair[2];
943
944 if (socketpair(AF_UNIX, fl, 0, pair) == -1)
945 err(1, "socketpair");
946 if ((pid = fork()) == -1)
947 err(1, "fork");
948
949 if (pid == 0) {
950 setproctitle("%s", title);
951 /* change working directory to the cache directory */
952 if (fchdir(cachefd) == -1)
953 err(1, "fchdir");
954 if (!filemode && timeout > 0)
955 alarm(timeout);
956 close(pair[1]);
957 *fd = pair[0];
958 } else {
959 close(pair[0]);
960 *fd = pair[1];
961 }
962 return pid;
963 }
964
965 void
suicide(int sig)966 suicide(int sig __attribute__((unused)))
967 {
968 killme = 1;
969 }
970
971 #define NPFD 4
972
973 int
main(int argc,char * argv[])974 main(int argc, char *argv[])
975 {
976 int rc, c, i, st, hangup = 0;
977 int procfd, rsyncfd, httpfd, rrdpfd;
978 pid_t pid, procpid, rsyncpid, httppid, rrdppid;
979 struct pollfd pfd[NPFD];
980 struct msgbuf *queues[NPFD];
981 struct ibuf *b, *httpbuf = NULL, *procbuf = NULL;
982 struct ibuf *rrdpbuf = NULL, *rsyncbuf = NULL;
983 char *rsync_prog = "openrsync";
984 char *bind_addr = NULL;
985 const char *cachedir = NULL, *outputdir = NULL;
986 const char *errs, *name;
987 const char *skiplistfile = NULL;
988 struct vrp_tree vrps = RB_INITIALIZER(&vrps);
989 struct vsp_tree vsps = RB_INITIALIZER(&vsps);
990 struct brk_tree brks = RB_INITIALIZER(&brks);
991 struct vap_tree vaps = RB_INITIALIZER(&vaps);
992 struct rusage ru;
993 struct timespec start_time, now_time;
994
995 clock_gettime(CLOCK_MONOTONIC, &start_time);
996
997 /* If started as root, priv-drop to _rpki-client */
998 if (getuid() == 0) {
999 struct passwd *pw;
1000
1001 pw = getpwnam("_rpki-client");
1002 if (!pw)
1003 errx(1, "no _rpki-client user to revoke to");
1004 if (setgroups(1, &pw->pw_gid) == -1 ||
1005 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 ||
1006 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
1007 err(1, "unable to revoke privs");
1008 }
1009 cachedir = RPKI_PATH_BASE_DIR;
1010 outputdir = RPKI_PATH_OUT_DIR;
1011 repo_timeout = timeout / 4;
1012 skiplistfile = DEFAULT_SKIPLIST_FILE;
1013
1014 if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd "
1015 "proc exec unveil", NULL) == -1)
1016 err(1, "pledge");
1017
1018 while ((c = getopt(argc, argv, "Ab:Bcd:e:fH:jmnoP:Rs:S:t:T:vVx")) != -1)
1019 switch (c) {
1020 case 'A':
1021 excludeaspa = 1;
1022 break;
1023 case 'b':
1024 bind_addr = optarg;
1025 break;
1026 case 'B':
1027 outformats |= FORMAT_BIRD;
1028 break;
1029 case 'c':
1030 outformats |= FORMAT_CSV;
1031 break;
1032 case 'd':
1033 cachedir = optarg;
1034 break;
1035 case 'e':
1036 rsync_prog = optarg;
1037 break;
1038 case 'f':
1039 filemode = 1;
1040 noop = 1;
1041 break;
1042 case 'H':
1043 shortlistmode = 1;
1044 load_shortlist(optarg);
1045 break;
1046 case 'j':
1047 outformats |= FORMAT_JSON;
1048 break;
1049 case 'm':
1050 outformats |= FORMAT_OMETRIC;
1051 break;
1052 case 'n':
1053 noop = 1;
1054 break;
1055 case 'o':
1056 outformats |= FORMAT_OPENBGPD;
1057 break;
1058 case 'P':
1059 evaluation_time = strtonum(optarg, X509_TIME_MIN + 1,
1060 X509_TIME_MAX, &errs);
1061 if (errs)
1062 errx(1, "-P: time in seconds %s", errs);
1063 break;
1064 case 'R':
1065 rrdpon = 0;
1066 break;
1067 case 's':
1068 timeout = strtonum(optarg, 0, 24*60*60, &errs);
1069 if (errs)
1070 errx(1, "-s: %s", errs);
1071 if (timeout == 0)
1072 repo_timeout = 24*60*60;
1073 else
1074 repo_timeout = timeout / 4;
1075 break;
1076 case 'S':
1077 skiplistfile = optarg;
1078 break;
1079 case 't':
1080 if (talsz >= TALSZ_MAX)
1081 err(1, "too many tal files specified");
1082 tals[talsz++] = optarg;
1083 break;
1084 case 'T':
1085 bird_tablename = optarg;
1086 break;
1087 case 'v':
1088 verbose++;
1089 break;
1090 case 'V':
1091 fprintf(stderr, "rpki-client %s\n", RPKI_VERSION);
1092 return 0;
1093 case 'x':
1094 experimental = 1;
1095 break;
1096 default:
1097 goto usage;
1098 }
1099
1100 argv += optind;
1101 argc -= optind;
1102
1103 if (!filemode) {
1104 if (argc == 1)
1105 outputdir = argv[0];
1106 else if (argc > 1)
1107 goto usage;
1108
1109 if (outputdir == NULL) {
1110 warnx("output directory required");
1111 goto usage;
1112 }
1113 } else {
1114 if (argc == 0)
1115 goto usage;
1116 outputdir = NULL;
1117 }
1118
1119 if (cachedir == NULL) {
1120 warnx("cache directory required");
1121 goto usage;
1122 }
1123
1124 signal(SIGPIPE, SIG_IGN);
1125
1126 if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1)
1127 err(1, "cache directory %s", cachedir);
1128 if (outputdir != NULL) {
1129 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1)
1130 err(1, "output directory %s", outputdir);
1131 if (outformats == 0)
1132 outformats = FORMAT_OPENBGPD;
1133 }
1134
1135 check_fs_size(cachefd, cachedir);
1136
1137 if (talsz == 0)
1138 talsz = tal_load_default();
1139 if (talsz == 0)
1140 err(1, "no TAL files found in %s", "/etc/rpki");
1141
1142 /* Load optional constraint files sitting next to the TALs. */
1143 constraints_load();
1144
1145 /*
1146 * Create the file reader as a jailed child process.
1147 * It will be responsible for reading all of the files (ROAs,
1148 * manifests, certificates, etc.) and returning contents.
1149 */
1150
1151 procpid = process_start("parser", &procfd);
1152 if (procpid == 0) {
1153 if (!filemode)
1154 proc_parser(procfd);
1155 else
1156 proc_filemode(procfd);
1157 }
1158
1159 /* Constraints are only needed in the filemode and parser processes. */
1160 constraints_unload();
1161
1162 /*
1163 * Create a process that will do the rsync'ing.
1164 * This process is responsible for making sure that all the
1165 * repositories referenced by a certificate manifest (or the
1166 * TAL) exists and has been downloaded.
1167 */
1168
1169 if (!noop) {
1170 rsyncpid = process_start("rsync", &rsyncfd);
1171 if (rsyncpid == 0) {
1172 close(procfd);
1173 proc_rsync(rsync_prog, bind_addr, rsyncfd);
1174 }
1175 } else {
1176 rsyncfd = -1;
1177 rsyncpid = -1;
1178 }
1179
1180 /*
1181 * Create a process that will fetch data via https.
1182 * With every request the http process receives a file descriptor
1183 * where the data should be written to.
1184 */
1185
1186 if (!noop && rrdpon) {
1187 httppid = process_start("http", &httpfd);
1188
1189 if (httppid == 0) {
1190 close(procfd);
1191 close(rsyncfd);
1192 proc_http(bind_addr, httpfd);
1193 }
1194 } else {
1195 httpfd = -1;
1196 httppid = -1;
1197 }
1198
1199 /*
1200 * Create a process that will process RRDP.
1201 * The rrdp process requires the http process to fetch the various
1202 * XML files and does this via the main process.
1203 */
1204
1205 if (!noop && rrdpon) {
1206 rrdppid = process_start("rrdp", &rrdpfd);
1207 if (rrdppid == 0) {
1208 close(procfd);
1209 close(rsyncfd);
1210 close(httpfd);
1211 proc_rrdp(rrdpfd);
1212 }
1213 } else {
1214 rrdpfd = -1;
1215 rrdppid = -1;
1216 }
1217
1218 if (!filemode && timeout > 0) {
1219 /*
1220 * Commit suicide eventually
1221 * cron will normally start a new one
1222 */
1223 alarm(timeout);
1224 signal(SIGALRM, suicide);
1225
1226 /* give up a bit before the hard timeout and try to finish up */
1227 if (!noop)
1228 deadline = getmonotime() + timeout - repo_timeout / 2;
1229 }
1230
1231 if (pledge("stdio rpath wpath cpath fattr sendfd unveil", NULL) == -1)
1232 err(1, "pledge");
1233
1234 msgbuf_init(&procq);
1235 msgbuf_init(&rsyncq);
1236 msgbuf_init(&httpq);
1237 msgbuf_init(&rrdpq);
1238 procq.fd = procfd;
1239 rsyncq.fd = rsyncfd;
1240 httpq.fd = httpfd;
1241 rrdpq.fd = rrdpfd;
1242
1243 /*
1244 * The main process drives the top-down scan to leaf ROAs using
1245 * data downloaded by the rsync process and parsed by the
1246 * parsing process.
1247 */
1248
1249 pfd[0].fd = procfd;
1250 queues[0] = &procq;
1251 pfd[1].fd = rsyncfd;
1252 queues[1] = &rsyncq;
1253 pfd[2].fd = httpfd;
1254 queues[2] = &httpq;
1255 pfd[3].fd = rrdpfd;
1256 queues[3] = &rrdpq;
1257
1258 load_skiplist(skiplistfile);
1259
1260 /*
1261 * Prime the process with our TAL files.
1262 * These will (hopefully) contain links to manifests and we
1263 * can get the ball rolling.
1264 */
1265
1266 for (i = 0; i < talsz; i++)
1267 queue_add_file(tals[i], RTYPE_TAL, i);
1268
1269 if (filemode) {
1270 while (*argv != NULL)
1271 queue_add_file(*argv++, RTYPE_FILE, 0);
1272
1273 if (unveil(cachedir, "r") == -1)
1274 err(1, "unveil cachedir");
1275 } else {
1276 if (unveil(outputdir, "rwc") == -1)
1277 err(1, "unveil outputdir");
1278 if (unveil(cachedir, "rwc") == -1)
1279 err(1, "unveil cachedir");
1280 }
1281 if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1)
1282 err(1, "unveil");
1283
1284 /* change working directory to the cache directory */
1285 if (fchdir(cachefd) == -1)
1286 err(1, "fchdir");
1287
1288 while (entity_queue > 0 && !killme) {
1289 int polltim;
1290
1291 polltim = repo_check_timeout(INFTIM);
1292
1293 for (i = 0; i < NPFD; i++) {
1294 pfd[i].events = POLLIN;
1295 if (msgbuf_queuelen(queues[i]) > 0)
1296 pfd[i].events |= POLLOUT;
1297 }
1298
1299 if (poll(pfd, NPFD, polltim) == -1) {
1300 if (errno == EINTR)
1301 continue;
1302 err(1, "poll");
1303 }
1304
1305 for (i = 0; i < NPFD; i++) {
1306 if (pfd[i].revents & (POLLERR|POLLNVAL)) {
1307 warnx("poll[%d]: bad fd", i);
1308 hangup = 1;
1309 }
1310 if (pfd[i].revents & POLLHUP)
1311 hangup = 1;
1312 if (pfd[i].revents & POLLOUT) {
1313 switch (msgbuf_write(queues[i])) {
1314 case 0:
1315 warnx("write[%d]: "
1316 "connection closed", i);
1317 hangup = 1;
1318 break;
1319 case -1:
1320 warn("write[%d]", i);
1321 hangup = 1;
1322 break;
1323 }
1324 }
1325 }
1326 if (hangup)
1327 break;
1328
1329 /*
1330 * Check the rsync and http process.
1331 * This means that one of our modules has completed
1332 * downloading and we can flush the module requests into
1333 * the parser process.
1334 */
1335
1336 if ((pfd[1].revents & POLLIN)) {
1337 b = io_buf_read(rsyncfd, &rsyncbuf);
1338 if (b != NULL) {
1339 unsigned int id;
1340 int ok;
1341
1342 io_read_buf(b, &id, sizeof(id));
1343 io_read_buf(b, &ok, sizeof(ok));
1344 rsync_finish(id, ok);
1345 ibuf_free(b);
1346 }
1347 }
1348
1349 if ((pfd[2].revents & POLLIN)) {
1350 b = io_buf_read(httpfd, &httpbuf);
1351 if (b != NULL) {
1352 unsigned int id;
1353 enum http_result res;
1354 char *last_mod;
1355
1356 io_read_buf(b, &id, sizeof(id));
1357 io_read_buf(b, &res, sizeof(res));
1358 io_read_str(b, &last_mod);
1359 http_finish(id, res, last_mod);
1360 free(last_mod);
1361 ibuf_free(b);
1362 }
1363 }
1364
1365 /*
1366 * Handle RRDP requests here.
1367 */
1368 if ((pfd[3].revents & POLLIN)) {
1369 b = io_buf_read(rrdpfd, &rrdpbuf);
1370 if (b != NULL) {
1371 rrdp_process(b);
1372 ibuf_free(b);
1373 }
1374 }
1375
1376 /*
1377 * The parser has finished something for us.
1378 * Dequeue these one by one.
1379 */
1380
1381 if ((pfd[0].revents & POLLIN)) {
1382 b = io_buf_read(procfd, &procbuf);
1383 if (b != NULL) {
1384 entity_process(b, &stats, &vrps, &brks, &vaps,
1385 &vsps);
1386 ibuf_free(b);
1387 }
1388 }
1389 }
1390
1391 signal(SIGALRM, SIG_DFL);
1392 if (killme) {
1393 syslog(LOG_CRIT|LOG_DAEMON,
1394 "excessive runtime (%d seconds), giving up", timeout);
1395 errx(1, "excessive runtime (%d seconds), giving up", timeout);
1396 }
1397
1398 /*
1399 * For clean-up, close the input for the parser and rsync
1400 * process.
1401 * This will cause them to exit, then we reap them.
1402 */
1403
1404 close(procfd);
1405 close(rsyncfd);
1406 close(httpfd);
1407 close(rrdpfd);
1408
1409 rc = 0;
1410 for (;;) {
1411 pid = waitpid(WAIT_ANY, &st, 0);
1412 if (pid == -1) {
1413 if (errno == EINTR)
1414 continue;
1415 if (errno == ECHILD)
1416 break;
1417 err(1, "wait");
1418 }
1419
1420 if (pid == procpid)
1421 name = "parser";
1422 else if (pid == rsyncpid)
1423 name = "rsync";
1424 else if (pid == httppid)
1425 name = "http";
1426 else if (pid == rrdppid)
1427 name = "rrdp";
1428 else
1429 name = "unknown";
1430
1431 if (WIFSIGNALED(st)) {
1432 warnx("%s terminated signal %d", name, WTERMSIG(st));
1433 rc = 1;
1434 } else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) {
1435 warnx("%s process exited abnormally", name);
1436 rc = 1;
1437 }
1438 }
1439
1440 /* processing did not finish because of error */
1441 if (entity_queue != 0)
1442 errx(1, "not all files processed, giving up");
1443
1444 /* if processing in filemode the process is done, no cleanup */
1445 if (filemode)
1446 return rc;
1447
1448 logx("all files parsed: generating output");
1449
1450 if (!noop)
1451 repo_cleanup(&fpt, cachefd);
1452
1453 clock_gettime(CLOCK_MONOTONIC, &now_time);
1454 timespecsub(&now_time, &start_time, &stats.elapsed_time);
1455 if (getrusage(RUSAGE_SELF, &ru) == 0) {
1456 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &stats.user_time);
1457 TIMEVAL_TO_TIMESPEC(&ru.ru_stime, &stats.system_time);
1458 }
1459 if (getrusage(RUSAGE_CHILDREN, &ru) == 0) {
1460 struct timespec ts;
1461
1462 TIMEVAL_TO_TIMESPEC(&ru.ru_utime, &ts);
1463 timespecadd(&stats.user_time, &ts, &stats.user_time);
1464 TIMEVAL_TO_TIMESPEC(&ru.ru_stime, &ts);
1465 timespecadd(&stats.system_time, &ts, &stats.system_time);
1466 }
1467
1468 /* change working directory to the output directory */
1469 if (fchdir(outdirfd) == -1)
1470 err(1, "fchdir output dir");
1471
1472 for (i = 0; i < talsz; i++) {
1473 repo_tal_stats_collect(sum_stats, i, &talstats[i]);
1474 repo_tal_stats_collect(sum_stats, i, &stats.repo_tal_stats);
1475 }
1476 repo_stats_collect(sum_repostats, &stats.repo_stats);
1477
1478 if (outputfiles(&vrps, &brks, &vaps, &vsps, &stats))
1479 rc = 1;
1480
1481 printf("Processing time %lld seconds "
1482 "(%lld seconds user, %lld seconds system)\n",
1483 (long long)stats.elapsed_time.tv_sec,
1484 (long long)stats.user_time.tv_sec,
1485 (long long)stats.system_time.tv_sec);
1486 printf("Skiplist entries: %u\n", stats.skiplistentries);
1487 printf("Route Origin Authorizations: %u (%u failed parse, %u "
1488 "invalid)\n", stats.repo_tal_stats.roas,
1489 stats.repo_tal_stats.roas_fail,
1490 stats.repo_tal_stats.roas_invalid);
1491 printf("AS Provider Attestations: %u (%u failed parse, %u "
1492 "invalid)\n", stats.repo_tal_stats.aspas,
1493 stats.repo_tal_stats.aspas_fail,
1494 stats.repo_tal_stats.aspas_invalid);
1495 if (experimental) {
1496 printf("Signed Prefix Lists: %u "
1497 "(%u failed parse, %u invalid)\n",
1498 stats.repo_tal_stats.spls, stats.repo_tal_stats.spls_fail,
1499 stats.repo_tal_stats.spls_invalid);
1500 }
1501 printf("BGPsec Router Certificates: %u\n", stats.repo_tal_stats.brks);
1502 printf("Certificates: %u (%u invalid)\n",
1503 stats.repo_tal_stats.certs, stats.repo_tal_stats.certs_fail);
1504 printf("Trust Anchor Locators: %u (%u invalid)\n",
1505 stats.tals, talsz - stats.tals);
1506 printf("Manifests: %u (%u failed parse, %u seqnum gaps)\n",
1507 stats.repo_tal_stats.mfts, stats.repo_tal_stats.mfts_fail,
1508 stats.repo_tal_stats.mfts_gap);
1509 printf("Certificate revocation lists: %u\n", stats.repo_tal_stats.crls);
1510 printf("Ghostbuster records: %u\n", stats.repo_tal_stats.gbrs);
1511 printf("Trust Anchor Keys: %u\n", stats.repo_tal_stats.taks);
1512 printf("Repositories: %u\n", stats.repos);
1513 printf("New files moved into validated cache: %u\n",
1514 stats.repo_stats.new_files);
1515 printf("Cleanup: removed %u files, %u directories\n"
1516 "Repository cleanup: kept %u and removed %u superfluous files\n",
1517 stats.repo_stats.del_files, stats.repo_stats.del_dirs,
1518 stats.repo_stats.extra_files, stats.repo_stats.del_extra_files);
1519 printf("VRP Entries: %u (%u unique)\n", stats.repo_tal_stats.vrps,
1520 stats.repo_tal_stats.vrps_uniqs);
1521 printf("VAP Entries: %u (%u unique, %u overflowed)\n",
1522 stats.repo_tal_stats.vaps, stats.repo_tal_stats.vaps_uniqs,
1523 stats.repo_tal_stats.vaps_overflowed);
1524 printf("VSP Entries: %u (%u unique)\n", stats.repo_tal_stats.vsps,
1525 stats.repo_tal_stats.vsps_uniqs);
1526
1527 /* Memory cleanup. */
1528 repo_free();
1529
1530 return rc;
1531
1532 usage:
1533 fprintf(stderr,
1534 "usage: rpki-client [-ABcjmnoRVvx] [-b sourceaddr] [-d cachedir]"
1535 " [-e rsync_prog]\n"
1536 " [-H fqdn] [-P epoch] [-S skiplist] [-s timeout]"
1537 " [-T table]\n"
1538 " [-t tal] [outputdir]\n"
1539 " rpki-client [-Vv] [-d cachedir] [-j] [-t tal] -f file ..."
1540 "\n");
1541 return 1;
1542 }
1543