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