main.c revision 1.161
1/* $OpenBSD: main.c,v 1.161 2021/11/04 11:32:55 claudio 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/socket.h> 22#include <sys/resource.h> 23#include <sys/statvfs.h> 24#include <sys/tree.h> 25#include <sys/wait.h> 26 27#include <assert.h> 28#include <err.h> 29#include <errno.h> 30#include <dirent.h> 31#include <fcntl.h> 32#include <fnmatch.h> 33#include <poll.h> 34#include <pwd.h> 35#include <stdio.h> 36#include <stdlib.h> 37#include <signal.h> 38#include <string.h> 39#include <limits.h> 40#include <syslog.h> 41#include <unistd.h> 42#include <imsg.h> 43 44#include "extern.h" 45#include "version.h" 46 47/* 48 * Maximum number of TAL files we'll load. 49 */ 50#define TALSZ_MAX 8 51 52const char *tals[TALSZ_MAX]; 53const char *taldescs[TALSZ_MAX]; 54size_t talsz; 55 56size_t entity_queue; 57int timeout = 60*60; 58volatile sig_atomic_t killme; 59void suicide(int sig); 60 61static struct filepath_tree fpt = RB_INITIALIZER(&fpt); 62static struct msgbuf procq, rsyncq, httpq, rrdpq; 63static int cachefd, outdirfd; 64 65const char *bird_tablename = "ROAS"; 66 67int verbose; 68int noop; 69int rrdpon = 1; 70 71struct stats stats; 72 73/* 74 * Log a message to stderr if and only if "verbose" is non-zero. 75 * This uses the err(3) functionality. 76 */ 77void 78logx(const char *fmt, ...) 79{ 80 va_list ap; 81 82 if (verbose && fmt != NULL) { 83 va_start(ap, fmt); 84 vwarnx(fmt, ap); 85 va_end(ap); 86 } 87} 88 89void 90entity_free(struct entity *ent) 91{ 92 if (ent == NULL) 93 return; 94 95 free(ent->data); 96 free(ent->file); 97 free(ent); 98} 99 100/* 101 * Read a queue entity from the descriptor. 102 * Matched by entity_buffer_req(). 103 * The pointer must be passed entity_free(). 104 */ 105void 106entity_read_req(struct ibuf *b, struct entity *ent) 107{ 108 io_read_buf(b, &ent->type, sizeof(ent->type)); 109 io_read_buf(b, &ent->talid, sizeof(ent->talid)); 110 io_read_str(b, &ent->file); 111 io_read_buf(b, &ent->has_data, sizeof(ent->has_data)); 112 if (ent->has_data) 113 io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz); 114} 115 116/* 117 * Write the queue entity. 118 * Matched by entity_read_req(). 119 */ 120static void 121entity_write_req(const struct entity *ent) 122{ 123 struct ibuf *b; 124 125 if (filepath_add(&fpt, ent->file) == 0) { 126 warnx("%s: File already visited", ent->file); 127 entity_queue--; 128 return; 129 } 130 131 b = io_new_buffer(); 132 io_simple_buffer(b, &ent->type, sizeof(ent->type)); 133 io_simple_buffer(b, &ent->talid, sizeof(ent->talid)); 134 io_str_buffer(b, ent->file); 135 io_simple_buffer(b, &ent->has_data, sizeof(int)); 136 if (ent->has_data) 137 io_buf_buffer(b, ent->data, ent->datasz); 138 io_close_buffer(&procq, b); 139} 140 141/* 142 * Scan through all queued requests and see which ones are in the given 143 * repo, then flush those into the parser process. 144 */ 145void 146entityq_flush(struct entityq *q, struct repo *rp) 147{ 148 struct entity *p, *np; 149 150 TAILQ_FOREACH_SAFE(p, q, entries, np) { 151 char *file = p->file; 152 153 /* 154 * XXX fixup path here since the repo may change 155 * during load because of fallback. In that case 156 * the file path changes as well since RRDP and RSYNC 157 * can not share a common repo. 158 */ 159 p->file = repo_filename(rp, file); 160 if (p->file == NULL) 161 err(1, "can't construct repo filename"); 162 free(file); 163 164 entity_write_req(p); 165 TAILQ_REMOVE(q, p, entries); 166 entity_free(p); 167 } 168} 169 170/* 171 * Add the heap-allocated file to the queue for processing. 172 */ 173static void 174entityq_add(char *file, enum rtype type, struct repo *rp, 175 unsigned char *data, size_t datasz, int talid) 176{ 177 struct entity *p; 178 179 if ((p = calloc(1, sizeof(struct entity))) == NULL) 180 err(1, NULL); 181 182 p->type = type; 183 p->talid = talid; 184 p->file = file; 185 p->has_data = data != NULL; 186 if (p->has_data) { 187 p->data = data; 188 p->datasz = datasz; 189 } 190 191 entity_queue++; 192 193 /* 194 * Write to the queue if there's no repo or the repo has already 195 * been loaded else enqueue it for later. 196 */ 197 198 if (rp == NULL || !repo_queued(rp, p)) { 199 /* 200 * XXX fixup path here since for repo path the 201 * file path has not yet been fixed here. 202 * This is a quick way to make this work but in 203 * the long run repos need to be passed to the parser. 204 */ 205 if (rp != NULL) { 206 file = p->file; 207 p->file = repo_filename(rp, file); 208 if (p->file == NULL) 209 err(1, "can't construct repo filename from %s", 210 file); 211 free(file); 212 } 213 entity_write_req(p); 214 entity_free(p); 215 } 216} 217 218static void 219rrdp_file_resp(size_t id, int ok) 220{ 221 enum rrdp_msg type = RRDP_FILE; 222 struct ibuf *b; 223 224 b = io_new_buffer(); 225 io_simple_buffer(b, &type, sizeof(type)); 226 io_simple_buffer(b, &id, sizeof(id)); 227 io_simple_buffer(b, &ok, sizeof(ok)); 228 io_close_buffer(&rrdpq, b); 229} 230 231void 232rrdp_fetch(size_t id, const char *uri, const char *local, 233 struct rrdp_session *s) 234{ 235 enum rrdp_msg type = RRDP_START; 236 struct ibuf *b; 237 238 b = io_new_buffer(); 239 io_simple_buffer(b, &type, sizeof(type)); 240 io_simple_buffer(b, &id, sizeof(id)); 241 io_str_buffer(b, local); 242 io_str_buffer(b, uri); 243 io_str_buffer(b, s->session_id); 244 io_simple_buffer(b, &s->serial, sizeof(s->serial)); 245 io_str_buffer(b, s->last_mod); 246 io_close_buffer(&rrdpq, b); 247} 248 249/* 250 * Request a repository sync via rsync URI to directory local. 251 */ 252void 253rsync_fetch(size_t id, const char *uri, const char *local) 254{ 255 struct ibuf *b; 256 257 b = io_new_buffer(); 258 io_simple_buffer(b, &id, sizeof(id)); 259 io_str_buffer(b, local); 260 io_str_buffer(b, uri); 261 io_close_buffer(&rsyncq, b); 262} 263 264/* 265 * Request a file from a https uri, data is written to the file descriptor fd. 266 */ 267void 268http_fetch(size_t id, const char *uri, const char *last_mod, int fd) 269{ 270 struct ibuf *b; 271 272 b = io_new_buffer(); 273 io_simple_buffer(b, &id, sizeof(id)); 274 io_str_buffer(b, uri); 275 io_str_buffer(b, last_mod); 276 /* pass file as fd */ 277 b->fd = fd; 278 io_close_buffer(&httpq, b); 279} 280 281/* 282 * Request some XML file on behalf of the rrdp parser. 283 * Create a pipe and pass the pipe endpoints to the http and rrdp process. 284 */ 285static void 286rrdp_http_fetch(size_t id, const char *uri, const char *last_mod) 287{ 288 enum rrdp_msg type = RRDP_HTTP_INI; 289 struct ibuf *b; 290 int pi[2]; 291 292 if (pipe2(pi, O_CLOEXEC | O_NONBLOCK) == -1) 293 err(1, "pipe"); 294 295 b = io_new_buffer(); 296 io_simple_buffer(b, &type, sizeof(type)); 297 io_simple_buffer(b, &id, sizeof(id)); 298 b->fd = pi[0]; 299 io_close_buffer(&rrdpq, b); 300 301 http_fetch(id, uri, last_mod, pi[1]); 302} 303 304void 305rrdp_http_done(size_t id, enum http_result res, const char *last_mod) 306{ 307 enum rrdp_msg type = RRDP_HTTP_FIN; 308 struct ibuf *b; 309 310 /* RRDP request, relay response over to the rrdp process */ 311 b = io_new_buffer(); 312 io_simple_buffer(b, &type, sizeof(type)); 313 io_simple_buffer(b, &id, sizeof(id)); 314 io_simple_buffer(b, &res, sizeof(res)); 315 io_str_buffer(b, last_mod); 316 io_close_buffer(&rrdpq, b); 317} 318 319/* 320 * Add a file (CER, ROA, CRL) from an MFT file, RFC 6486. 321 * These are always relative to the directory in which "mft" sits. 322 */ 323static void 324queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type) 325{ 326 char *cp, *nfile; 327 328 /* Construct local path from filename. */ 329 cp = strrchr(mft, '/'); 330 assert(cp != NULL); 331 assert(cp - mft < INT_MAX); 332 if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1) 333 err(1, NULL); 334 335 /* 336 * Since we're from the same directory as the MFT file, we know 337 * that the repository has already been loaded. 338 */ 339 340 entityq_add(nfile, type, NULL, NULL, 0, -1); 341} 342 343/* 344 * Loops over queue_add_from_mft() for all files. 345 * The order here is important: we want to parse the revocation 346 * list *before* we parse anything else. 347 * FIXME: set the type of file in the mftfile so that we don't need to 348 * keep doing the check (this should be done in the parser, where we 349 * check the suffix anyway). 350 */ 351static void 352queue_add_from_mft_set(const struct mft *mft) 353{ 354 size_t i, sz; 355 const struct mftfile *f; 356 357 for (i = 0; i < mft->filesz; i++) { 358 f = &mft->files[i]; 359 sz = strlen(f->file); 360 assert(sz > 4); 361 if (strcasecmp(f->file + sz - 4, ".crl") != 0) 362 continue; 363 queue_add_from_mft(mft->file, f, RTYPE_CRL); 364 } 365 366 for (i = 0; i < mft->filesz; i++) { 367 f = &mft->files[i]; 368 sz = strlen(f->file); 369 assert(sz > 4); 370 if (strcasecmp(f->file + sz - 4, ".crl") == 0) 371 continue; 372 else if (strcasecmp(f->file + sz - 4, ".cer") == 0) 373 queue_add_from_mft(mft->file, f, RTYPE_CER); 374 else if (strcasecmp(f->file + sz - 4, ".roa") == 0) 375 queue_add_from_mft(mft->file, f, RTYPE_ROA); 376 else if (strcasecmp(f->file + sz - 4, ".gbr") == 0) 377 queue_add_from_mft(mft->file, f, RTYPE_GBR); 378 else 379 logx("%s: unsupported file type: %s", mft->file, 380 f->file); 381 } 382} 383 384/* 385 * Add a local TAL file (RFC 7730) to the queue of files to fetch. 386 */ 387static void 388queue_add_tal(const char *file, int id) 389{ 390 unsigned char *buf; 391 char *nfile; 392 size_t len; 393 394 if ((nfile = strdup(file)) == NULL) 395 err(1, NULL); 396 buf = load_file(file, &len); 397 if (buf == NULL) { 398 warn("%s", file); 399 return; 400 } 401 402 /* Not in a repository, so directly add to queue. */ 403 entityq_add(nfile, RTYPE_TAL, NULL, buf, len, id); 404} 405 406/* 407 * Add URIs (CER) from a TAL file, RFC 8630. 408 */ 409static void 410queue_add_from_tal(struct tal *tal) 411{ 412 struct repo *repo; 413 unsigned char *data; 414 415 assert(tal->urisz); 416 417 if ((taldescs[tal->id] = strdup(tal->descr)) == NULL) 418 err(1, NULL); 419 420 /* Look up the repository. */ 421 repo = ta_lookup(tal); 422 423 /* steal the pkey from the tal structure */ 424 data = tal->pkey; 425 tal->pkey = NULL; 426 entityq_add(NULL, RTYPE_CER, repo, data, 427 tal->pkeysz, tal->id); 428} 429 430/* 431 * Add a manifest (MFT) found in an X509 certificate, RFC 6487. 432 */ 433static void 434queue_add_from_cert(const struct cert *cert) 435{ 436 struct repo *repo; 437 char *nfile; 438 439 repo = repo_lookup(cert->repo, rrdpon ? cert->notify : NULL); 440 if (repo == NULL) { 441 warnx("%s: repository lookup failed", cert->repo); 442 return; 443 } 444 445 if ((nfile = strdup(cert->mft)) == NULL) 446 err(1, NULL); 447 entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, -1); 448} 449 450/* 451 * Process parsed content. 452 * For non-ROAs, we grok for more data. 453 * For ROAs, we want to extract the valid info. 454 * In all cases, we gather statistics. 455 */ 456static void 457entity_process(struct ibuf *b, struct stats *st, struct vrp_tree *tree, 458 struct brk_tree *brktree) 459{ 460 enum rtype type; 461 struct tal *tal; 462 struct cert *cert; 463 struct mft *mft; 464 struct roa *roa; 465 int c; 466 467 /* 468 * For most of these, we first read whether there's any content 469 * at all---this means that the syntactic parse failed (X509 470 * certificate, for example). 471 * We follow that up with whether the resources didn't parse. 472 */ 473 io_read_buf(b, &type, sizeof(type)); 474 475 switch (type) { 476 case RTYPE_TAL: 477 st->tals++; 478 tal = tal_read(b); 479 queue_add_from_tal(tal); 480 tal_free(tal); 481 break; 482 case RTYPE_CER: 483 st->certs++; 484 io_read_buf(b, &c, sizeof(c)); 485 if (c == 0) { 486 st->certs_fail++; 487 break; 488 } 489 cert = cert_read(b); 490 if (cert->purpose == CERT_PURPOSE_CA) { 491 /* 492 * Process the revocation list from the 493 * certificate *first*, since it might mark that 494 * we're revoked and then we don't want to 495 * process the MFT. 496 */ 497 queue_add_from_cert(cert); 498 } else if (cert->purpose == CERT_PURPOSE_BGPSEC_ROUTER) { 499 cert_insert_brks(brktree, cert); 500 st->brks++; 501 } else 502 st->certs_fail++; 503 cert_free(cert); 504 break; 505 case RTYPE_MFT: 506 st->mfts++; 507 io_read_buf(b, &c, sizeof(c)); 508 if (c == 0) { 509 st->mfts_fail++; 510 break; 511 } 512 mft = mft_read(b); 513 if (mft->stale) 514 st->mfts_stale++; 515 queue_add_from_mft_set(mft); 516 mft_free(mft); 517 break; 518 case RTYPE_CRL: 519 st->crls++; 520 break; 521 case RTYPE_ROA: 522 st->roas++; 523 io_read_buf(b, &c, sizeof(c)); 524 if (c == 0) { 525 st->roas_fail++; 526 break; 527 } 528 roa = roa_read(b); 529 if (roa->valid) 530 roa_insert_vrps(tree, roa, &st->vrps, &st->uniqs); 531 else 532 st->roas_invalid++; 533 roa_free(roa); 534 break; 535 case RTYPE_GBR: 536 st->gbrs++; 537 break; 538 default: 539 errx(1, "unknown entity type %d", type); 540 } 541 542 entity_queue--; 543} 544 545static void 546rrdp_process(struct ibuf *b) 547{ 548 enum rrdp_msg type; 549 enum publish_type pt; 550 struct rrdp_session s; 551 char *uri, *last_mod, *data; 552 char hash[SHA256_DIGEST_LENGTH]; 553 size_t dsz, id; 554 int ok; 555 556 io_read_buf(b, &type, sizeof(type)); 557 io_read_buf(b, &id, sizeof(id)); 558 559 switch (type) { 560 case RRDP_END: 561 io_read_buf(b, &ok, sizeof(ok)); 562 rrdp_finish(id, ok); 563 break; 564 case RRDP_HTTP_REQ: 565 io_read_str(b, &uri); 566 io_read_str(b, &last_mod); 567 rrdp_http_fetch(id, uri, last_mod); 568 break; 569 case RRDP_SESSION: 570 io_read_str(b, &s.session_id); 571 io_read_buf(b, &s.serial, sizeof(s.serial)); 572 io_read_str(b, &s.last_mod); 573 rrdp_save_state(id, &s); 574 free(s.session_id); 575 free(s.last_mod); 576 break; 577 case RRDP_FILE: 578 io_read_buf(b, &pt, sizeof(pt)); 579 if (pt != PUB_ADD) 580 io_read_buf(b, &hash, sizeof(hash)); 581 io_read_str(b, &uri); 582 io_read_buf_alloc(b, (void **)&data, &dsz); 583 584 ok = rrdp_handle_file(id, pt, uri, hash, sizeof(hash), 585 data, dsz); 586 rrdp_file_resp(id, ok); 587 588 free(uri); 589 free(data); 590 break; 591 default: 592 errx(1, "unexpected rrdp response"); 593 } 594} 595 596/* 597 * Assign filenames ending in ".tal" in "/etc/rpki" into "tals", 598 * returning the number of files found and filled-in. 599 * This may be zero. 600 * Don't exceded "max" filenames. 601 */ 602static size_t 603tal_load_default(void) 604{ 605 static const char *confdir = "/etc/rpki"; 606 size_t s = 0; 607 char *path; 608 DIR *dirp; 609 struct dirent *dp; 610 611 dirp = opendir(confdir); 612 if (dirp == NULL) 613 err(1, "open %s", confdir); 614 while ((dp = readdir(dirp)) != NULL) { 615 if (fnmatch("*.tal", dp->d_name, FNM_PERIOD) == FNM_NOMATCH) 616 continue; 617 if (s >= TALSZ_MAX) 618 err(1, "too many tal files found in %s", 619 confdir); 620 if (asprintf(&path, "%s/%s", confdir, dp->d_name) == -1) 621 err(1, NULL); 622 tals[s++] = path; 623 } 624 closedir(dirp); 625 return s; 626} 627 628static void 629check_fs_size(int fd, const char *cachedir) 630{ 631 struct statvfs fs; 632 const long long minsize = 500 * 1024 * 1024; 633 const long long minnode = 300 * 1000; 634 635 if (fstatvfs(fd, &fs) == -1) 636 err(1, "statfs %s", cachedir); 637 638 if (fs.f_bavail < minsize / fs.f_frsize || fs.f_favail < minnode) { 639 fprintf(stderr, "WARNING: rpki-client may need more than " 640 "the availabe disk space\n" 641 "on the file-system holding %s.\n", cachedir); 642 fprintf(stderr, "available space: %lldkB, " 643 "suggested minimum %lldkB\n", 644 (long long)fs.f_bavail * fs.f_frsize / 1024, 645 minsize / 1024); 646 fprintf(stderr, "available inodes %lld, " 647 "suggested minimum %lld\n\n", 648 (long long)fs.f_favail, minnode); 649 fflush(stderr); 650 } 651} 652 653void 654suicide(int sig __attribute__((unused))) 655{ 656 killme = 1; 657} 658 659#define NPFD 4 660 661int 662main(int argc, char *argv[]) 663{ 664 int rc, c, st, proc, rsync, http, rrdp, ok, hangup = 0; 665 int fl = SOCK_STREAM | SOCK_CLOEXEC | SOCK_NONBLOCK; 666 size_t i, id; 667 pid_t pid, procpid, rsyncpid, httppid, rrdppid; 668 int fd[2]; 669 struct pollfd pfd[NPFD]; 670 struct msgbuf *queues[NPFD]; 671 struct ibuf *b, *httpbuf = NULL, *procbuf = NULL; 672 struct ibuf *rrdpbuf = NULL, *rsyncbuf = NULL; 673 char *rsync_prog = "openrsync"; 674 char *bind_addr = NULL; 675 const char *cachedir = NULL, *outputdir = NULL; 676 const char *errs, *name; 677 const char *file = NULL; 678 struct vrp_tree vrps = RB_INITIALIZER(&vrps); 679 struct brk_tree brks = RB_INITIALIZER(&brks); 680 struct rusage ru; 681 struct timeval start_time, now_time; 682 683 gettimeofday(&start_time, NULL); 684 685 /* If started as root, priv-drop to _rpki-client */ 686 if (getuid() == 0) { 687 struct passwd *pw; 688 689 pw = getpwnam("_rpki-client"); 690 if (!pw) 691 errx(1, "no _rpki-client user to revoke to"); 692 if (setgroups(1, &pw->pw_gid) == -1 || 693 setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1 || 694 setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1) 695 err(1, "unable to revoke privs"); 696 } 697 cachedir = RPKI_PATH_BASE_DIR; 698 outputdir = RPKI_PATH_OUT_DIR; 699 700 if (pledge("stdio rpath wpath cpath inet fattr dns sendfd recvfd " 701 "proc exec unveil", NULL) == -1) 702 err(1, "pledge"); 703 704 while ((c = getopt(argc, argv, "b:Bcd:e:f:jnorRs:t:T:vV")) != -1) 705 switch (c) { 706 case 'b': 707 bind_addr = optarg; 708 break; 709 case 'B': 710 outformats |= FORMAT_BIRD; 711 break; 712 case 'c': 713 outformats |= FORMAT_CSV; 714 break; 715 case 'd': 716 cachedir = optarg; 717 break; 718 case 'e': 719 rsync_prog = optarg; 720 break; 721 case 'f': 722 file = optarg; 723 noop = 1; 724 break; 725 case 'j': 726 outformats |= FORMAT_JSON; 727 break; 728 case 'n': 729 noop = 1; 730 break; 731 case 'o': 732 outformats |= FORMAT_OPENBGPD; 733 break; 734 case 'R': 735 rrdpon = 0; 736 break; 737 case 'r': 738 rrdpon = 1; 739 break; 740 case 's': 741 timeout = strtonum(optarg, 0, 24*60*60, &errs); 742 if (errs) 743 errx(1, "-s: %s", errs); 744 break; 745 case 't': 746 if (talsz >= TALSZ_MAX) 747 err(1, 748 "too many tal files specified"); 749 tals[talsz++] = optarg; 750 break; 751 case 'T': 752 bird_tablename = optarg; 753 break; 754 case 'v': 755 verbose++; 756 break; 757 case 'V': 758 fprintf(stderr, "rpki-client %s\n", RPKI_VERSION); 759 return 0; 760 default: 761 goto usage; 762 } 763 764 argv += optind; 765 argc -= optind; 766 if (argc == 1) 767 outputdir = argv[0]; 768 else if (argc > 1) 769 goto usage; 770 771 signal(SIGPIPE, SIG_IGN); 772 773 if (cachedir == NULL) { 774 warnx("cache directory required"); 775 goto usage; 776 } 777 if (outputdir == NULL) { 778 warnx("output directory required"); 779 goto usage; 780 } 781 782 if ((cachefd = open(cachedir, O_RDONLY | O_DIRECTORY)) == -1) 783 err(1, "cache directory %s", cachedir); 784 if ((outdirfd = open(outputdir, O_RDONLY | O_DIRECTORY)) == -1) 785 err(1, "output directory %s", outputdir); 786 787 check_fs_size(cachefd, cachedir); 788 789 if (outformats == 0) 790 outformats = FORMAT_OPENBGPD; 791 792 if (talsz == 0) 793 talsz = tal_load_default(); 794 if (talsz == 0) 795 err(1, "no TAL files found in %s", "/etc/rpki"); 796 797 /* 798 * Create the file reader as a jailed child process. 799 * It will be responsible for reading all of the files (ROAs, 800 * manifests, certificates, etc.) and returning contents. 801 */ 802 803 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 804 err(1, "socketpair"); 805 if ((procpid = fork()) == -1) 806 err(1, "fork"); 807 808 if (procpid == 0) { 809 close(fd[1]); 810 811 setproctitle("parser"); 812 /* change working directory to the cache directory */ 813 if (fchdir(cachefd) == -1) 814 err(1, "fchdir"); 815 816 if (timeout) 817 alarm(timeout); 818 819 /* Only allow access to the cache directory. */ 820 if (unveil(".", "r") == -1) 821 err(1, "%s: unveil", cachedir); 822 if (pledge("stdio rpath", NULL) == -1) 823 err(1, "pledge"); 824 proc_parser(fd[0]); 825 errx(1, "parser process returned"); 826 } 827 828 close(fd[0]); 829 proc = fd[1]; 830 831 /* 832 * Create a process that will do the rsync'ing. 833 * This process is responsible for making sure that all the 834 * repositories referenced by a certificate manifest (or the 835 * TAL) exists and has been downloaded. 836 */ 837 838 if (!noop) { 839 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 840 err(1, "socketpair"); 841 if ((rsyncpid = fork()) == -1) 842 err(1, "fork"); 843 844 if (rsyncpid == 0) { 845 close(proc); 846 close(fd[1]); 847 848 setproctitle("rsync"); 849 /* change working directory to the cache directory */ 850 if (fchdir(cachefd) == -1) 851 err(1, "fchdir"); 852 853 if (timeout) 854 alarm(timeout); 855 856 if (pledge("stdio rpath proc exec unveil", NULL) == -1) 857 err(1, "pledge"); 858 859 proc_rsync(rsync_prog, bind_addr, fd[0]); 860 errx(1, "rsync process returned"); 861 } 862 863 close(fd[0]); 864 rsync = fd[1]; 865 } else { 866 rsync = -1; 867 rsyncpid = -1; 868 } 869 870 /* 871 * Create a process that will fetch data via https. 872 * With every request the http process receives a file descriptor 873 * where the data should be written to. 874 */ 875 876 if (!noop) { 877 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 878 err(1, "socketpair"); 879 if ((httppid = fork()) == -1) 880 err(1, "fork"); 881 882 if (httppid == 0) { 883 close(proc); 884 close(rsync); 885 close(fd[1]); 886 887 setproctitle("http"); 888 /* change working directory to the cache directory */ 889 if (fchdir(cachefd) == -1) 890 err(1, "fchdir"); 891 892 if (timeout) 893 alarm(timeout); 894 895 if (pledge("stdio rpath inet dns recvfd", NULL) == -1) 896 err(1, "pledge"); 897 898 proc_http(bind_addr, fd[0]); 899 errx(1, "http process returned"); 900 } 901 902 close(fd[0]); 903 http = fd[1]; 904 } else { 905 http = -1; 906 httppid = -1; 907 } 908 909 /* 910 * Create a process that will process RRDP. 911 * The rrdp process requires the http process to fetch the various 912 * XML files and does this via the main process. 913 */ 914 915 if (!noop && rrdpon) { 916 if (socketpair(AF_UNIX, fl, 0, fd) == -1) 917 err(1, "socketpair"); 918 if ((rrdppid = fork()) == -1) 919 err(1, "fork"); 920 921 if (rrdppid == 0) { 922 close(proc); 923 close(rsync); 924 close(http); 925 close(fd[1]); 926 927 setproctitle("rrdp"); 928 /* change working directory to the cache directory */ 929 if (fchdir(cachefd) == -1) 930 err(1, "fchdir"); 931 932 if (timeout) 933 alarm(timeout); 934 935 if (pledge("stdio recvfd", NULL) == -1) 936 err(1, "pledge"); 937 938 proc_rrdp(fd[0]); 939 /* NOTREACHED */ 940 } 941 942 close(fd[0]); 943 rrdp = fd[1]; 944 } else { 945 rrdp = -1; 946 rrdppid = -1; 947 } 948 949 if (timeout) { 950 /* 951 * Commit suicide eventually 952 * cron will normally start a new one 953 */ 954 alarm(timeout); 955 signal(SIGALRM, suicide); 956 } 957 958 /* TODO unveil cachedir and outputdir, no other access allowed */ 959 if (pledge("stdio rpath wpath cpath fattr sendfd", NULL) == -1) 960 err(1, "pledge"); 961 962 msgbuf_init(&procq); 963 msgbuf_init(&rsyncq); 964 msgbuf_init(&httpq); 965 msgbuf_init(&rrdpq); 966 procq.fd = proc; 967 rsyncq.fd = rsync; 968 httpq.fd = http; 969 rrdpq.fd = rrdp; 970 971 /* 972 * The main process drives the top-down scan to leaf ROAs using 973 * data downloaded by the rsync process and parsed by the 974 * parsing process. 975 */ 976 977 pfd[0].fd = proc; 978 queues[0] = &procq; 979 pfd[1].fd = rsync; 980 queues[1] = &rsyncq; 981 pfd[2].fd = http; 982 queues[2] = &httpq; 983 pfd[3].fd = rrdp; 984 queues[3] = &rrdpq; 985 986 /* 987 * Prime the process with our TAL file. 988 * This will contain (hopefully) links to our manifest and we 989 * can get the ball rolling. 990 */ 991 992 for (i = 0; i < talsz; i++) 993 queue_add_tal(tals[i], i); 994 995 /* change working directory to the cache directory */ 996 if (fchdir(cachefd) == -1) 997 err(1, "fchdir"); 998 999 while (entity_queue > 0 && !killme) { 1000 for (i = 0; i < NPFD; i++) { 1001 pfd[i].events = POLLIN; 1002 if (queues[i]->queued) 1003 pfd[i].events |= POLLOUT; 1004 } 1005 1006 if ((c = poll(pfd, NPFD, INFTIM)) == -1) { 1007 if (errno == EINTR) 1008 continue; 1009 err(1, "poll"); 1010 } 1011 1012 for (i = 0; i < NPFD; i++) { 1013 if (pfd[i].revents & (POLLERR|POLLNVAL)) 1014 errx(1, "poll[%zu]: bad fd", i); 1015 if (pfd[i].revents & POLLHUP) { 1016 warnx("poll[%zu]: hangup", i); 1017 hangup = 1; 1018 } 1019 if (pfd[i].revents & POLLOUT) { 1020 switch (msgbuf_write(queues[i])) { 1021 case 0: 1022 errx(1, "write[%zu]: " 1023 "connection closed", i); 1024 case -1: 1025 err(1, "write[%zu]", i); 1026 } 1027 } 1028 } 1029 if (hangup) 1030 break; 1031 1032 /* 1033 * Check the rsync and http process. 1034 * This means that one of our modules has completed 1035 * downloading and we can flush the module requests into 1036 * the parser process. 1037 */ 1038 1039 if ((pfd[1].revents & POLLIN)) { 1040 b = io_buf_read(rsync, &rsyncbuf); 1041 if (b != NULL) { 1042 io_read_buf(b, &id, sizeof(id)); 1043 io_read_buf(b, &ok, sizeof(ok)); 1044 rsync_finish(id, ok); 1045 ibuf_free(b); 1046 } 1047 } 1048 1049 if ((pfd[2].revents & POLLIN)) { 1050 b = io_buf_read(http, &httpbuf); 1051 if (b != NULL) { 1052 enum http_result res; 1053 char *last_mod; 1054 1055 io_read_buf(b, &id, sizeof(id)); 1056 io_read_buf(b, &res, sizeof(res)); 1057 io_read_str(b, &last_mod); 1058 http_finish(id, res, last_mod); 1059 free(last_mod); 1060 ibuf_free(b); 1061 } 1062 } 1063 1064 /* 1065 * Handle RRDP requests here. 1066 */ 1067 if ((pfd[3].revents & POLLIN)) { 1068 b = io_buf_read(rrdp, &rrdpbuf); 1069 if (b != NULL) { 1070 rrdp_process(b); 1071 ibuf_free(b); 1072 } 1073 } 1074 1075 /* 1076 * The parser has finished something for us. 1077 * Dequeue these one by one. 1078 */ 1079 1080 if ((pfd[0].revents & POLLIN)) { 1081 b = io_buf_read(proc, &procbuf); 1082 if (b != NULL) { 1083 entity_process(b, &stats, &vrps, &brks); 1084 ibuf_free(b); 1085 } 1086 } 1087 } 1088 1089 signal(SIGALRM, SIG_DFL); 1090 if (killme) { 1091 syslog(LOG_CRIT|LOG_DAEMON, 1092 "excessive runtime (%d seconds), giving up", timeout); 1093 errx(1, "excessive runtime (%d seconds), giving up", timeout); 1094 } 1095 1096 /* 1097 * For clean-up, close the input for the parser and rsync 1098 * process. 1099 * This will cause them to exit, then we reap them. 1100 */ 1101 1102 close(proc); 1103 close(rsync); 1104 close(http); 1105 close(rrdp); 1106 1107 rc = 0; 1108 for (;;) { 1109 pid = waitpid(WAIT_ANY, &st, 0); 1110 if (pid == -1) { 1111 if (errno == EINTR) 1112 continue; 1113 if (errno == ECHILD) 1114 break; 1115 err(1, "wait"); 1116 } 1117 1118 if (pid == procpid) 1119 name = "parser"; 1120 else if (pid == rsyncpid) 1121 name = "rsync"; 1122 else if (pid == httppid) 1123 name = "http"; 1124 else if (pid == rrdppid) 1125 name = "rrdp"; 1126 else 1127 name = "unknown"; 1128 1129 if (WIFSIGNALED(st)) { 1130 warnx("%s terminated signal %d", name, WTERMSIG(st)); 1131 rc = 1; 1132 } else if (!WIFEXITED(st) || WEXITSTATUS(st) != 0) { 1133 warnx("%s process exited abnormally", name); 1134 rc = 1; 1135 } 1136 } 1137 1138 /* processing did not finish because of error */ 1139 if (entity_queue != 0) 1140 return 1; 1141 1142 logx("all files parsed: generating output"); 1143 1144 repo_cleanup(&fpt); 1145 1146 gettimeofday(&now_time, NULL); 1147 timersub(&now_time, &start_time, &stats.elapsed_time); 1148 if (getrusage(RUSAGE_SELF, &ru) == 0) { 1149 stats.user_time = ru.ru_utime; 1150 stats.system_time = ru.ru_stime; 1151 } 1152 if (getrusage(RUSAGE_CHILDREN, &ru) == 0) { 1153 timeradd(&stats.user_time, &ru.ru_utime, &stats.user_time); 1154 timeradd(&stats.system_time, &ru.ru_stime, &stats.system_time); 1155 } 1156 1157 /* change working directory to the output directory */ 1158 if (fchdir(outdirfd) == -1) 1159 err(1, "fchdir output dir"); 1160 1161 if (outputfiles(&vrps, &brks, &stats)) 1162 rc = 1; 1163 1164 logx("Processing time %lld seconds " 1165 "(%lld seconds user, %lld seconds system)", 1166 (long long)stats.elapsed_time.tv_sec, 1167 (long long)stats.user_time.tv_sec, 1168 (long long)stats.system_time.tv_sec); 1169 logx("Route Origin Authorizations: %zu (%zu failed parse, %zu invalid)", 1170 stats.roas, stats.roas_fail, stats.roas_invalid); 1171 logx("BGPsec Router Certificates: %zu", stats.brks); 1172 logx("Certificates: %zu (%zu invalid)", 1173 stats.certs, stats.certs_fail); 1174 logx("Trust Anchor Locators: %zu (%zu invalid)", 1175 stats.tals, talsz - stats.tals); 1176 logx("Manifests: %zu (%zu failed parse, %zu stale)", 1177 stats.mfts, stats.mfts_fail, stats.mfts_stale); 1178 logx("Certificate revocation lists: %zu", stats.crls); 1179 logx("Ghostbuster records: %zu", stats.gbrs); 1180 logx("Repositories: %zu", stats.repos); 1181 logx("Cleanup: removed %zu files, %zu directories", 1182 stats.del_files, stats.del_dirs); 1183 logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs); 1184 1185 /* Memory cleanup. */ 1186 repo_free(); 1187 1188 return rc; 1189 1190usage: 1191 fprintf(stderr, 1192 "usage: rpki-client [-BcjnoRrVv] [-b sourceaddr] [-d cachedir]" 1193 " [-e rsync_prog]\n" 1194 " [-s timeout] [-T table] [-t tal]" 1195 " [outputdir]\n"); 1196 return 1; 1197} 1198