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