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